diff --git a/.DS_Store b/.DS_Store index dfa9dfe..96551bb 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/auto-bid-admin/src/apis/scrap.ts b/auto-bid-admin/src/apis/scrap.ts new file mode 100644 index 0000000..c78ead5 --- /dev/null +++ b/auto-bid-admin/src/apis/scrap.ts @@ -0,0 +1,47 @@ +import { handleError, handleSuccess } from "."; +import axios from "../lib/axios"; +import { IScrapConfig, IWebBid } from "../system/type"; +import { removeFalsyValues } from "../utils"; + +export const createScrapConfig = async ( + bid: Omit< + IScrapConfig, + "id" | "created_at" | "updated_at" | "scrap_items" + > & { web_id: IWebBid["id"] } +) => { + const newData = removeFalsyValues(bid); + + try { + const { data } = await axios({ + url: "scrap-configs", + withCredentials: true, + method: "POST", + data: newData, + }); + + handleSuccess(data); + + return data; + } catch (error) { + handleError(error); + } +}; + +export const updateScrapConfig = async (scrapConfig: Partial) => { + const { search_url, keywords, id } = removeFalsyValues(scrapConfig); + + try { + const { data } = await axios({ + url: "scrap-configs/" + id, + withCredentials: true, + method: "PUT", + data: { search_url, keywords }, + }); + + handleSuccess(data); + + return data; + } catch (error) { + handleError(error); + } +}; diff --git a/auto-bid-admin/src/components/dashboard/working-page.tsx b/auto-bid-admin/src/components/dashboard/working-page.tsx index 399f74a..00b28c9 100644 --- a/auto-bid-admin/src/components/dashboard/working-page.tsx +++ b/auto-bid-admin/src/components/dashboard/working-page.tsx @@ -217,26 +217,32 @@ export default function WorkingPage({ data, socket }: IWorkingPageProps) { - - - {statusLabel()} - + + + + {statusLabel()} + - + {isIBid(data) ? extractDomainSmart(data.web_bid.origin_url) - : extractDomainSmart(data.origin_url) - )} - size="xs" - > - {isIBid(data) - ? extractDomainSmart(data.web_bid.origin_url) - : extractDomainSmart(data.origin_url)} - + : extractDomainSmart(data.origin_url)} + + + + {isIBid(data) && moment(data.close_time).isSame(moment(), "day") && ( +
+ )}
diff --git a/auto-bid-admin/src/components/web-bid/scrap-config.modal.tsx b/auto-bid-admin/src/components/web-bid/scrap-config.modal.tsx new file mode 100644 index 0000000..00f95f6 --- /dev/null +++ b/auto-bid-admin/src/components/web-bid/scrap-config.modal.tsx @@ -0,0 +1,163 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { + Button, + LoadingOverlay, + Modal, + ModalProps, + Textarea, + TextInput, +} from "@mantine/core"; +import { useForm, zodResolver } from "@mantine/form"; +import _ from "lodash"; +import { useEffect, useRef, useState } from "react"; +import { z } from "zod"; +import { createScrapConfig, updateScrapConfig } from "../../apis/scrap"; +import { useConfirmStore } from "../../lib/zustand/use-confirm"; +import { IScrapConfig, IWebBid } from "../../system/type"; +export interface IScrapConfigModelProps extends ModalProps { + data: IWebBid | null; + onUpdated?: () => void; +} + +const schema = z.object({ + search_url: z + .string() + .url({ message: "Url is invalid" }) + .min(1, { message: "Url is required" }), + keywords: z + .string({ message: "Keyword is required" }) + .min(1, { message: "Keyword is required" }) + .optional(), +}); + +export default function ScrapConfigModal({ + data, + onUpdated, + ...props +}: IScrapConfigModelProps) { + const form = useForm({ + validate: zodResolver(schema), + }); + + const [loading, setLoading] = useState(false); + + const prevData = useRef(data?.scrap_config); + + const { setConfirm } = useConfirmStore(); + + const handleSubmit = async (values: typeof form.values) => { + if (data?.scrap_config) { + setConfirm({ + title: "Update ?", + message: `This config will be update`, + handleOk: async () => { + setLoading(true); + const result = await updateScrapConfig({ + ...values, + id: data.scrap_config.id, + }); + setLoading(false); + + if (!result) return; + + props.onClose(); + + if (onUpdated) { + onUpdated(); + } + }, + okButton: { + color: "blue", + value: "Update", + }, + }); + } else { + setLoading(true); + const result = await createScrapConfig({ + ...values, + web_id: data?.id || 0, + }); + setLoading(false); + + if (!result) return; + + props.onClose(); + + if (onUpdated) { + onUpdated(); + } + } + }; + + useEffect(() => { + form.reset(); + if (!data) return; + + form.setValues(data.scrap_config); + + prevData.current = data.scrap_config; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [data]); + + useEffect(() => { + if (!props.opened) { + form.reset(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [props.opened]); + + return ( + Scrap config} + centered + > +
+ + + - - `; - - inputsContainer.insertAdjacentHTML("afterbegin", otherEls); - - // 2. Tạo và chèn Current Price ngay sau #url-col - const currentPriceDiv = document.createElement("div"); - currentPriceDiv.className = "col"; - currentPriceDiv.innerHTML = ` - - - `; - - urlCol.parentNode.insertBefore(currentPriceDiv, urlCol.nextSibling); - - formElements.quantity.value = data?.quantity || 1; - formElements.plusPrice.value = data?.plus_price || 0; -}; - -const showInfo = async (model, formElements) => { - const key = await getKey(); - if (!key) { - showKey(); - return; - } - - try { - const response = await fetch(`${CONFIG.API_BASE_URL}/bids/${model}`, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: key, - }, - }); - - const result = await response.json(); - - if (!result || result?.status_code !== 200 || !result?.data) { - if (result.status_code !== 404) { - alert(result.message); - } - - PREV_DATA = null; - return null; - } - - formElements.maxPrice.value = result.data.max_price; - - createInfoColumn(result.data, formElements); - - PREV_DATA = result; - return result; - } catch (error) { - alert("Error: " + error.message); - console.error("API Error:", error); - } -}; - -(async () => { - await showPage(); - - const formElements = { - url: document.querySelector("#form-bid #url"), - maxPrice: document.querySelector("#form-bid #maxPrice"), - plusPrice: document.querySelector("#form-bid #plusPrice"), - quantity: document.querySelector("#form-bid #quantity"), - createBtn: document.querySelector("#form-bid #createBtn"), - form: document.querySelector("#form-bid form"), - }; - - const style = document.createElement("link"); - style.rel = "stylesheet"; - style.href = chrome.runtime.getURL("assets/css/index.css"); - document.head.appendChild(style); - - const script = document.createElement("script"); - script.type = "module"; - script.src = chrome.runtime.getURL("pages/popup/popup.js"); - script.defer = true; - - document.body.appendChild(script); - - handleSaveKey(); - - const currentUrl = window.location.href; - - const model = extractModelId(currentUrl); - - if (!model) return; - - // set url on form - formElements.url.value = currentUrl; - - await showInfo(model, formElements); - handleChangeTitleButton(!!PREV_DATA, formElements); - - formElements.form.addEventListener("submit", (e) => - PREV_DATA - ? handleUpdate(e, formElements, PREV_DATA.data.id) - : handleCreate(e, formElements) - ); -})(); diff --git a/bid-extension/manifest.json b/bid-extension/manifest.json deleted file mode 100644 index e59b97a..0000000 --- a/bid-extension/manifest.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "manifest_version": 3, - "name": "Bid Extension", - "version": "1.0", - "description": "Bid Extension", - "action": { - "default_popup": "pages/popup/popup.html", - "default_icon": { - "16": "assets/icons/16.png", - "32": "assets/icons/32.png", - "128": "assets/icons/128.png" - } - }, - "background": { - "service_worker": "background.js" - }, - "permissions": ["storage"], - "host_permissions": ["http://*/*", "https://*/*"], - "content_scripts": [ - { - "matches": [""], - "js": ["content.js"] - } - ], - "web_accessible_resources": [ - { - "resources": [ - "pages/popup/popup.html", - "pages/popup/popup.js", - "assets/css/index.css", - "config.js", - "assets/icons/*" - ], - "matches": [""] - } - ], - "icons": { - "16": "assets/icons/16.png", - "32": "assets/icons/32.png", - "128": "assets/icons/128.png" - } -} diff --git a/bid-extension/pages/popup/popup.html b/bid-extension/pages/popup/popup.html deleted file mode 100644 index 68ead10..0000000 --- a/bid-extension/pages/popup/popup.html +++ /dev/null @@ -1,170 +0,0 @@ -
- -
- -
- - - - -
-
-

Key

-
-
- - -
-
- -
-
-
diff --git a/bid-extension/pages/popup/popup.js b/bid-extension/pages/popup/popup.js deleted file mode 100644 index 34f60f0..0000000 --- a/bid-extension/pages/popup/popup.js +++ /dev/null @@ -1,17 +0,0 @@ -const handleToogle = () => { - const btn = document.getElementById("toggle-bid-extension"); - const panel = document.getElementById("bid-extension"); - - // Kiểm tra xem nút và panel có tồn tại hay không - if (btn && panel) { - btn.addEventListener("click", () => { - panel.style.display = panel.style.display === "none" ? "block" : "none"; - }); - } else { - console.error("Không tìm thấy nút hoặc panel!"); - } -}; - -// init(); - -handleToogle();