first commit

This commit is contained in:
Admin 2025-08-21 10:41:16 +07:00
parent 922362dc6f
commit a31a77d934
33 changed files with 541 additions and 23 deletions

7
.env.example Normal file
View File

@ -0,0 +1,7 @@
VITE_API_URL=""
VITE_API_TOKEN=""
VITE_API_SYNC_URL=""

View File

@ -0,0 +1 @@
function e(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}export{e as g};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
function h(n,e=[]){return Object.entries(n).reduce((r,[s,t])=>((t||e.includes(s))&&(r[s]=t),r),{})}function a(n){return new Promise(e=>setTimeout(e,n))}function l(n,e){const r=Math.floor(Math.random()*(e-n+1))+n;return a(r)}class u{role;listeners;constructor(e){this.role=e,this.listeners=new Map,chrome.runtime.onMessage.addListener((r,s,t)=>{if(r?.type&&this.listeners.has(r.type))return this.listeners.get(r.type)(r.payload,s,t),!0})}on(e,r){this.listeners.set(e,r)}send(e,r,s){const t={from:this.role,to:e,type:r,payload:s};(this.role==="popup"||this.role==="content")&&chrome.runtime.sendMessage(t),this.role==="background"&&(e==="content"?chrome.tabs.query({active:!0,currentWindow:!0},o=>{o[0]?.id&&chrome.tabs.sendMessage(o[0].id,t,()=>{chrome.runtime.lastError&&console.warn("Không gửi được tới content script:",chrome.runtime.lastError.message)})}):e==="popup"&&chrome.runtime.sendMessage(t,()=>{chrome.runtime.lastError&&console.warn("Không gửi được tới popup:",chrome.runtime.lastError.message)}))}sendToTab(e,r,s){if(this.role!=="background")throw new Error("sendToTab chỉ được gọi từ background");const t={from:this.role,to:"content",type:r,payload:s};chrome.tabs.sendMessage(e,t,()=>{chrome.runtime.lastError&&console.warn(`Không gửi được tới content script ở tab ${e}:`,chrome.runtime.lastError.message)})}waitForMessage(e,r=3e4){return new Promise((s,t)=>{let o;const i=c=>{clearTimeout(o),this.off(e,i),s(c)};o=setTimeout(()=>{this.off(e,i),t(new Error(`Timeout khi chờ message: ${e}`))},r),this.on(e,i)})}off(e,r){this.listeners.get(e)===r&&this.listeners.delete(e)}}export{u as M,l as a,a as d,h as r};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,17 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<script type="module" crossorigin src="/assets/popup.js"></script>
<link rel="modulepreload" crossorigin href="/assets/_commonjsHelpers-CqkleIqs.js">
<link rel="modulepreload" crossorigin href="/assets/product-api.service-BCmn_jbQ.js">
<link rel="modulepreload" crossorigin href="/assets/message.service-DcR3euAR.js">
<link rel="stylesheet" crossorigin href="/assets/popup-DfztxwQY.css">
</head>
<body>
<div id="root"></div>
</body>
</html>

View File

@ -0,0 +1,21 @@
{
"manifest_version": 3,
"name": "Auto post facebook extensions",
"version": "1.0",
"action": {
"default_popup": "index.html"
},
"background": {
"service_worker": "background/background.js",
"type": "module"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content/content.js"],
"type": "module"
}
],
"permissions": ["storage", "tabs", "activeTab", "scripting"]
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

13
package-lock.json generated
View File

@ -35,6 +35,7 @@
"react-hook-form": "^7.62.0",
"tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.12",
"use-debounce": "^10.0.5",
"webextension-polyfill": "^0.12.0",
"zod": "^4.0.17"
},
@ -6834,6 +6835,18 @@
}
}
},
"node_modules/use-debounce": {
"version": "10.0.5",
"resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-10.0.5.tgz",
"integrity": "sha512-Q76E3lnIV+4YT9AHcrHEHYmAd9LKwUAbPXDm7FlqVGDHiSOhX3RDjT8dm0AxbJup6WgOb1YEcKyCr11kBJR5KQ==",
"license": "MIT",
"engines": {
"node": ">= 16.0.0"
},
"peerDependencies": {
"react": "*"
}
},
"node_modules/use-sidecar": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",

View File

@ -43,6 +43,7 @@
"react-hook-form": "^7.62.0",
"tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.12",
"use-debounce": "^10.0.5",
"webextension-polyfill": "^0.12.0",
"zod": "^4.0.17"
},

View File

@ -0,0 +1 @@
function e(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}export{e as g};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
function h(n,e=[]){return Object.entries(n).reduce((r,[s,t])=>((t||e.includes(s))&&(r[s]=t),r),{})}function a(n){return new Promise(e=>setTimeout(e,n))}function l(n,e){const r=Math.floor(Math.random()*(e-n+1))+n;return a(r)}class u{role;listeners;constructor(e){this.role=e,this.listeners=new Map,chrome.runtime.onMessage.addListener((r,s,t)=>{if(r?.type&&this.listeners.has(r.type))return this.listeners.get(r.type)(r.payload,s,t),!0})}on(e,r){this.listeners.set(e,r)}send(e,r,s){const t={from:this.role,to:e,type:r,payload:s};(this.role==="popup"||this.role==="content")&&chrome.runtime.sendMessage(t),this.role==="background"&&(e==="content"?chrome.tabs.query({active:!0,currentWindow:!0},o=>{o[0]?.id&&chrome.tabs.sendMessage(o[0].id,t,()=>{chrome.runtime.lastError&&console.warn("Không gửi được tới content script:",chrome.runtime.lastError.message)})}):e==="popup"&&chrome.runtime.sendMessage(t,()=>{chrome.runtime.lastError&&console.warn("Không gửi được tới popup:",chrome.runtime.lastError.message)}))}sendToTab(e,r,s){if(this.role!=="background")throw new Error("sendToTab chỉ được gọi từ background");const t={from:this.role,to:"content",type:r,payload:s};chrome.tabs.sendMessage(e,t,()=>{chrome.runtime.lastError&&console.warn(`Không gửi được tới content script ở tab ${e}:`,chrome.runtime.lastError.message)})}waitForMessage(e,r=3e4){return new Promise((s,t)=>{let o;const i=c=>{clearTimeout(o),this.off(e,i),s(c)};o=setTimeout(()=>{this.off(e,i),t(new Error(`Timeout khi chờ message: ${e}`))},r),this.on(e,i)})}off(e,r){this.listeners.get(e)===r&&this.listeners.delete(e)}}export{u as M,l as a,a as d,h as r};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,17 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<script type="module" crossorigin src="/assets/popup.js"></script>
<link rel="modulepreload" crossorigin href="/assets/_commonjsHelpers-CqkleIqs.js">
<link rel="modulepreload" crossorigin href="/assets/product-api.service-BCmn_jbQ.js">
<link rel="modulepreload" crossorigin href="/assets/message.service-DcR3euAR.js">
<link rel="stylesheet" crossorigin href="/assets/popup-DfztxwQY.css">
</head>
<body>
<div id="root"></div>
</body>
</html>

View File

@ -0,0 +1,21 @@
{
"manifest_version": 3,
"name": "Auto post facebook extensions",
"version": "1.0",
"action": {
"default_popup": "index.html"
},
"background": {
"service_worker": "background/background.js",
"type": "module"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content/content.js"],
"type": "module"
}
],
"permissions": ["storage", "tabs", "activeTab", "scripting"]
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,8 +1 @@
[
{
"title": "Cisco 2911 Voice Bundle, Pvdm3-16, Uc License Pak, Fl- Cube10 - CISCO2911-V/K9",
"price": 3595,
"el": {},
"date": "2025-08-21T03:25:51.274Z"
}
]
[]

View File

@ -4,9 +4,6 @@ import type { IPost, ISyncItem } from "@/lib/utils";
class ProductApiService {
item_per_page = 10;
token =
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2ludC5pcHN1cHBseS5jb20uYXUvYXBpL2xvZ2luIiwiaWF0IjoxNzIxNjA5MTEzLCJleHAiOjMyMzUzMzcxMTMsIm5iZiI6MTcyMTYwOTExMywianRpIjoiWHpCZkZPc0ZJUlFxaEZvaiIsInN1YiI6MSwicHJ2IjoiYzhlZTFmYzg5ZTc3NWVjNGM3Mzg2NjdlNWJlMTdhNTkwYjZkNDBmYyJ9.kFFEPpdmNUp-kn_G3cIIc26bivO6tbfcvkpG9I8Im7M";
async index(filter?: {
skip?: number;
limit?: number;
@ -25,9 +22,7 @@ class ProductApiService {
return axios({
url: "transferGetData",
headers: {
Authorization: "Bearer " + this.token,
},
method: "POST",
data: {
urlAPI: "/api/ebay-listing/listing-get-list",
@ -46,9 +41,7 @@ class ProductApiService {
async get(data: IPost) {
return axios({
url: "transferGetData",
headers: {
Authorization: "Bearer " + this.token,
},
method: "POST",
data: {
urlAPI: "/api/product-model/get-info/" + data.id,

View File

@ -4,8 +4,6 @@ import { useQuery } from "@tanstack/react-query";
import { useMemo, useState } from "react";
import { productApi } from "@/api/product-api.service";
import { mapToIPost, type IPost } from "@/lib/utils";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
@ -32,6 +30,7 @@ import {
TableRow,
} from "@/components/ui/table";
import { removeFalsyValues } from "@/features/app";
import { mapToIPost, type IPost } from "@/lib/utils";
import MessageService from "@/services/message.service";
import {
ChevronLeft,
@ -43,6 +42,7 @@ import {
MoreHorizontal,
Search,
} from "lucide-react";
import { useDebounce } from "use-debounce";
import Loader from "./loader";
import ProductModal from "./product-modal";
@ -56,9 +56,11 @@ export function PostTable() {
const [currentPage, setCurrentPage] = useState(1);
const [isFilterModalOpen, setIsFilterModalOpen] = useState(false);
const [search] = useDebounce(searchTerm, 400);
const queryKey = useMemo(
() => ["products", { currentPage, searchTerm }],
[currentPage, searchTerm]
() => ["products", { currentPage, search }],
[currentPage, search]
);
// --- React Query fetch ---

View File

@ -3,8 +3,10 @@ import ax from "axios";
const axios = ax.create({
// Dev
baseURL: import.meta.env.VITE_API_URL,
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + import.meta.env.VITE_API_TOKEN,
},
});

View File

@ -4,6 +4,7 @@ import react from "@vitejs/plugin-react-swc";
import tailwindcss from "@tailwindcss/vite";
import path, { resolve } from "path";
import pkg from "./package.json";
import mnf from "./public/manifest.json";
// https://vite.dev/config/
export default defineConfig({
@ -14,7 +15,7 @@ export default defineConfig({
},
},
build: {
outDir: pkg.name,
outDir: `${pkg.name}_${mnf.version}`,
rollupOptions: {
input: {
popup: resolve(__dirname, "index.html"),

View File

@ -3,6 +3,7 @@ import fse from "fs-extra";
import path, { resolve } from "path";
import { defineConfig } from "vite";
import pkg from "./package.json";
import mnf from "./public/manifest.json";
export default defineConfig({
plugins: [
@ -10,7 +11,11 @@ export default defineConfig({
name: "copy-content-script",
closeBundle: async () => {
const src = resolve(__dirname, "dist-content/content/content.js");
const destDir = resolve(__dirname, pkg.name, "content");
const destDir = resolve(
__dirname,
`${pkg.name}_${mnf.version}`,
"content"
);
const dest = resolve(destDir, "content.js");
if (!fs.existsSync(src)) {
@ -25,6 +30,26 @@ export default defineConfig({
console.log(`✅ Copied content.js → ${dest}`);
},
},
{
name: "copy-release-folder",
closeBundle: async () => {
const buildDir = resolve(__dirname, `${pkg.name}_${mnf.version}`);
const releaseDir = resolve(
__dirname,
"releases",
`${pkg.name}_${mnf.version}`
);
if (!fs.existsSync(buildDir)) {
console.warn("⚠️ Build folder chưa được tạo:", buildDir);
return;
}
await fse.ensureDir(path.dirname(releaseDir));
await fse.copy(buildDir, releaseDir, { overwrite: true });
console.log(`📦 Copied ${buildDir}${releaseDir}`);
},
},
],
resolve: {
alias: {