-
+
dragAxisX.value, (newValue) => {
/>
dragAxisX.value, (newValue) => {
-
+
-
+
رنگ محصول
نارنجی
@@ -76,7 +81,6 @@ watch(() => dragAxisX.value, (newValue) => {
سفید
-
@@ -90,4 +94,4 @@ watch(() => dragAxisX.value, (newValue) => {
v-bind('clipPathPercent + "%"') 100%
);
}
-
\ No newline at end of file
+
diff --git a/frontend/components/product/ChatBox/AiLoading.vue b/frontend/components/product/ChatBox/AiLoading.vue
new file mode 100644
index 0000000..6dba1e2
--- /dev/null
+++ b/frontend/components/product/ChatBox/AiLoading.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/components/product/ChatBox/ChatBoxContainer.vue b/frontend/components/product/ChatBox/ChatBoxContainer.vue
new file mode 100644
index 0000000..fc01eca
--- /dev/null
+++ b/frontend/components/product/ChatBox/ChatBoxContainer.vue
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/product/ChatBox/ChatButton.vue b/frontend/components/product/ChatBox/ChatButton.vue
new file mode 100644
index 0000000..0ad5dcc
--- /dev/null
+++ b/frontend/components/product/ChatBox/ChatButton.vue
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/components/product/ChatBox/ChatInput.vue b/frontend/components/product/ChatBox/ChatInput.vue
new file mode 100644
index 0000000..5f1b73c
--- /dev/null
+++ b/frontend/components/product/ChatBox/ChatInput.vue
@@ -0,0 +1,305 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/components/product/ChatBox/ChatMessage.vue b/frontend/components/product/ChatBox/ChatMessage.vue
new file mode 100644
index 0000000..6a1db5c
--- /dev/null
+++ b/frontend/components/product/ChatBox/ChatMessage.vue
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+ {{ content }}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/components/product/ChatBox/CloseButton.vue b/frontend/components/product/ChatBox/CloseButton.vue
new file mode 100644
index 0000000..af2c23f
--- /dev/null
+++ b/frontend/components/product/ChatBox/CloseButton.vue
@@ -0,0 +1,34 @@
+
+
+
+
+
+ چت بات هوش مصنوعی
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/components/products/FilterButton.vue b/frontend/components/products/FilterButton.vue
index 097aa0f..74266ca 100644
--- a/frontend/components/products/FilterButton.vue
+++ b/frontend/components/products/FilterButton.vue
@@ -1,78 +1,18 @@
-
-
+
+
فیلتر محصولات
-
-
-
-
-
- Edit profile
-
-
- Make changes to your profile here. Click save when you're
- done.
-
-
-
- Name
-
-
-
-
-
- Username
-
-
-
-
-
-
- Save changes
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/frontend/components/ui/ToastContainer/ToastBox.vue b/frontend/components/ui/ToastContainer/ToastBox.vue
index 152a043..d274de6 100644
--- a/frontend/components/ui/ToastContainer/ToastBox.vue
+++ b/frontend/components/ui/ToastContainer/ToastBox.vue
@@ -1,17 +1,21 @@
-
- {{ message }}
+
+
+ {{ message }}
-
+
- {{ description }}
+ {{ options.description }}
diff --git a/frontend/components/ui/ToastContainer/index.vue b/frontend/components/ui/ToastContainer/index.vue
index 266d557..d05e921 100644
--- a/frontend/components/ui/ToastContainer/index.vue
+++ b/frontend/components/ui/ToastContainer/index.vue
@@ -14,6 +14,6 @@ const { toasts } = useToast();
:key="toast.id"
:id="toast.id"
:message="toast.message"
- :description="toast.description"
+ :options="toast.options"
/>
\ No newline at end of file
diff --git a/frontend/composables/api/auth/useOtp.ts b/frontend/composables/api/auth/useOtp.ts
index 7909ccc..4c7e806 100644
--- a/frontend/composables/api/auth/useOtp.ts
+++ b/frontend/composables/api/auth/useOtp.ts
@@ -13,7 +13,7 @@ export type OtpRequest = {
// methods
export const handleOtp = async (variables: OtpRequest) => {
- const { data } = await axios.post
(`${API_ENDPOINTS.account.send_otp}`, variables);
+ const { data } = await axios.post(`${API_ENDPOINTS.account.send_otp}`, variables);
return data;
};
diff --git a/frontend/composables/api/auth/useSignIn.ts b/frontend/composables/api/auth/useSignIn.ts
index 3ace4f1..3f5e4b8 100644
--- a/frontend/composables/api/auth/useSignIn.ts
+++ b/frontend/composables/api/auth/useSignIn.ts
@@ -14,7 +14,7 @@ export type SignInRequest = {
// methods
export const handleSignIn = async (variables: SignInRequest) => {
- const { data } = await axios.post(`${API_ENDPOINTS.auth.signin}/`, variables);
+ const { data } = await axios.post(`${API_ENDPOINTS.auth.signin}/`, variables);
return data;
};
diff --git a/frontend/composables/api/branch/useCreateBranch.ts b/frontend/composables/api/branch/useCreateBranch.ts
new file mode 100644
index 0000000..1d891b2
--- /dev/null
+++ b/frontend/composables/api/branch/useCreateBranch.ts
@@ -0,0 +1,33 @@
+// imports
+
+import { useMutation } from "@tanstack/vue-query";
+import axios from "~/configs/axios.config";
+import { API_ENDPOINTS } from "~/constants";
+
+// types
+
+export type CreateBranchRequest = {
+ name: string;
+ description: string;
+};
+
+// methods
+
+export const handleCreateBranch = async ({ name, description }: CreateBranchRequest) => {
+ const payload: CreateBranchRequest = {
+ name,
+ description,
+ };
+
+ await axios.post(API_ENDPOINTS.branch.createBranch, payload);
+};
+
+// composable
+
+const useCreateBranch = () => {
+ return useMutation({
+ mutationFn: (data: CreateBranchRequest) => handleCreateBranch(data),
+ });
+};
+
+export default useCreateBranch;
diff --git a/frontend/composables/api/branch/useGetBranch.ts b/frontend/composables/api/branch/useGetBranch.ts
new file mode 100644
index 0000000..50228b2
--- /dev/null
+++ b/frontend/composables/api/branch/useGetBranch.ts
@@ -0,0 +1,54 @@
+// imports
+
+import { useQuery } from "@tanstack/vue-query";
+import axios from "~/configs/axios.config";
+import { API_ENDPOINTS, QUERY_KEYS } from "~/constants";
+import type { ComputedRef } from "vue";
+
+// types
+
+export type GetBranchResponse = Branch;
+
+// methods
+
+export const handleGetBranch = async (
+ branchId: string,
+ page: string | undefined,
+ folderId: string | undefined,
+ sort: string | undefined,
+ signal: AbortSignal
+) => {
+
+ const { data } = await axios.get(`${API_ENDPOINTS.branch.get}/${branchId}`, {
+ signal,
+ params: {
+ sort_by: sort,
+ folder_id: folderId,
+ offset: ((!!page ? Number(page) : 1) * 20) - 20,
+ limit: 20
+ }
+ });
+ return data;
+};
+
+// composable
+
+const useGetBranch = (
+ branchId: ComputedRef,
+ page: ComputedRef,
+ folderId: ComputedRef,
+ sort: ComputedRef
+) => {
+ return useQuery({
+ queryKey: [QUERY_KEYS.branch, branchId, page, folderId, sort],
+ queryFn: ({ signal }) => handleGetBranch(
+ branchId.value,
+ page.value,
+ folderId.value,
+ sort.value,
+ signal
+ )
+ });
+};
+
+export default useGetBranch;
diff --git a/frontend/composables/api/branch/useGetBranches.ts b/frontend/composables/api/branch/useGetBranches.ts
new file mode 100644
index 0000000..d665d7a
--- /dev/null
+++ b/frontend/composables/api/branch/useGetBranches.ts
@@ -0,0 +1,29 @@
+// imports
+
+import { useQuery } from "@tanstack/vue-query";
+import axios from "~/configs/axios.config";
+import { API_ENDPOINTS, QUERY_KEYS } from "~/constants";
+
+// types
+
+export type GetBranchesResponse = Branch[];
+
+// methods
+
+export const handleGetBranches = async () => {
+ const { data } = await axios.get(`${API_ENDPOINTS.branch.getAll}`);
+
+ return data;
+};
+
+// composable
+
+const useGetBranches = () => {
+ return useQuery({
+ staleTime: 60 * 1000,
+ queryKey: [QUERY_KEYS.branches],
+ queryFn: () => handleGetBranches()
+ });
+};
+
+export default useGetBranches;
diff --git a/frontend/composables/api/branch/useGetUserBranches.ts b/frontend/composables/api/branch/useGetUserBranches.ts
new file mode 100644
index 0000000..42d928e
--- /dev/null
+++ b/frontend/composables/api/branch/useGetUserBranches.ts
@@ -0,0 +1,31 @@
+// imports
+
+import { useQuery } from "@tanstack/vue-query";
+import axios from "~/configs/axios.config";
+import { API_ENDPOINTS, QUERY_KEYS } from "~/constants";
+
+// types
+
+export type GetUserBranchesResponse = Branch[];
+
+// methods
+
+export const handleGetUserBranches = async () => {
+ const { data } = await axios.get(
+ `${API_ENDPOINTS.branch.getUserBranches}`
+ );
+
+ return data;
+};
+
+// composable
+
+const useGetUserBranches = () => {
+ return useQuery({
+ staleTime: 60 * 1000,
+ queryKey: [QUERY_KEYS.userBranches],
+ queryFn: () => handleGetUserBranches(),
+ });
+};
+
+export default useGetUserBranches;
diff --git a/frontend/composables/api/chat/useCreateChatMessage.ts b/frontend/composables/api/chat/useCreateChatMessage.ts
new file mode 100644
index 0000000..ee0d7d7
--- /dev/null
+++ b/frontend/composables/api/chat/useCreateChatMessage.ts
@@ -0,0 +1,116 @@
+// imports
+
+import { QueryClient, useMutation } from "@tanstack/vue-query";
+import type { InfiniteData } from "@tanstack/vue-query";
+import axios from "~/configs/axios.config";
+import { API_ENDPOINTS, MUTATION_KEYS, QUERY_KEYS } from "~/constants";
+
+// types
+
+export type CreateChatMessageRequest = {
+ productId: string | number;
+ new_message: string;
+};
+
+export type CreateChatMessageResponse = Chat[]
+
+// methods
+
+export const handleCreateChatMessage = async (variables: CreateChatMessageRequest) => {
+ const { data } = await axios.post(`${API_ENDPOINTS.chat.new_message}/${variables.productId}`, variables, {
+ headers: {
+ Authorization: `Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoyMTY3ODE2OTAwLCJpYXQiOjE3MzU4MTY5MDAsImp0aSI6ImQwN2E2Y2Y2NzgwZjRlNTE5NWIzOGQxMTAzYzU4NDQ3IiwidXNlcl9pZCI6NX0.slwd7ZSV7nUXEuDTYwwHUOo9ekCefwEEL4kVv2vSTFo`
+ }
+ });
+ return data;
+};
+
+// composable
+
+const useCreateChatMessage = (queryClient: QueryClient) => {
+ return useMutation({
+ mutationKey: [MUTATION_KEYS.create_chat],
+ mutationFn: (variables: CreateChatMessageRequest) => handleCreateChatMessage(variables),
+ onMutate: (newMessage) => {
+ const prevData = queryClient.getQueriesData({ queryKey: [QUERY_KEYS.chat] });
+
+ queryClient.setQueryData>>([QUERY_KEYS.chat], (oldData) => {
+ const lastPage = oldData!.pages[oldData!.pages.length - 1];
+
+ return {
+ pages: [
+ {
+ count: lastPage.count,
+ next: lastPage.next,
+ previous: lastPage.previous,
+ results: [
+ {
+ id: Date.now(),
+ content: newMessage.new_message,
+ sender: "user"
+ }
+ ]
+ },
+ ...oldData!.pages
+ ],
+ pageParams: [
+ ...oldData!.pageParams,
+ {
+ limit: 10,
+ offset: 0
+ }
+ ]
+ };
+ });
+
+
+ return { prevData: prevData ? prevData[0][1] : undefined };
+ },
+ onSuccess: (response) => {
+
+ queryClient.setQueryData>>([QUERY_KEYS.chat], (oldData) => {
+ if (oldData) {
+ const lastPage = oldData!.pages[oldData!.pages.length - 1];
+
+ return {
+ pages: [
+ {
+ count: lastPage.count,
+ next: lastPage.next,
+ previous: lastPage.previous,
+ results: {
+ ...response[0],
+ id: Date.now()
+ }
+ },
+ ...oldData!.pages
+ ],
+ pageParams: [
+ ...oldData!.pageParams,
+ {
+ limit: 10,
+ offset: 0
+ }
+ ]
+ };
+ }
+
+ return oldData;
+ });
+
+ },
+ onError: (err, newMessage, context) => {
+ if (context) {
+ queryClient.setQueryData(
+ [QUERY_KEYS.chat],
+ context.prevData
+ );
+ }
+ },
+ onSettled: (newMessage) => {
+ queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.chat] });
+ }
+ });
+};
+
+export default useCreateChatMessage;
diff --git a/frontend/composables/api/chat/useGetChat.ts b/frontend/composables/api/chat/useGetChat.ts
new file mode 100644
index 0000000..10bfc34
--- /dev/null
+++ b/frontend/composables/api/chat/useGetChat.ts
@@ -0,0 +1,60 @@
+// imports
+
+import { useInfiniteQuery, useQuery } from "@tanstack/vue-query";
+import axios from "~/configs/axios.config";
+import { API_ENDPOINTS, QUERY_KEYS } from "~/constants";
+import type { ComputedRef } from "vue";
+
+// types
+
+export type GetBranchResponse = ApiPaginated;
+
+// methods
+
+export const handleGetChat = async ({ productId, limit, offset }: {
+ productId: number | string,
+ limit: number,
+ offset: number
+}) => {
+ const { data } = await axios.get(`${API_ENDPOINTS.chat.messages}/${productId}`, {
+ params: {
+ offset,
+ limit
+ },
+ headers: {
+ Authorization: `Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoyMTY3ODE2OTAwLCJpYXQiOjE3MzU4MTY5MDAsImp0aSI6ImQwN2E2Y2Y2NzgwZjRlNTE5NWIzOGQxMTAzYzU4NDQ3IiwidXNlcl9pZCI6NX0.slwd7ZSV7nUXEuDTYwwHUOo9ekCefwEEL4kVv2vSTFo`
+ }
+ });
+ return data;
+};
+
+// composable
+
+const useGetBranch = (
+ productId: Ref,
+ enabled: Ref
+) => {
+ return useInfiniteQuery({
+ enabled,
+ queryKey: [QUERY_KEYS.chat],
+ initialPageParam: {
+ limit: 10,
+ offset: 0
+ },
+ queryFn: ({ pageParam }) => handleGetChat({
+ limit: pageParam.limit,
+ offset: pageParam.offset,
+ productId: productId.value
+ }),
+ getNextPageParam: (lastPage, pages) => {
+ if (!lastPage.next) return undefined;
+
+ return {
+ limit: 10,
+ offset: pages.length * 10
+ };
+ }
+ });
+};
+
+export default useGetBranch;
diff --git a/frontend/composables/api/documents/useAddDoc.ts b/frontend/composables/api/documents/useAddDoc.ts
new file mode 100644
index 0000000..ed1675f
--- /dev/null
+++ b/frontend/composables/api/documents/useAddDoc.ts
@@ -0,0 +1,45 @@
+// imports
+
+import { useMutation } from "@tanstack/vue-query";
+import axios from "~/configs/axios.config";
+import { API_ENDPOINTS } from "~/constants";
+
+// types
+
+export type AddDocRequest = {
+ name: string,
+ parent?: string,
+ branch: string | undefined,
+ type: {
+ title: "File" | "Folder",
+ icon: "bi:folder" | "bi:file-earmark"
+ },
+ content: File | undefined
+};
+
+// methods
+
+export const handleAddDoc = async (variables: AddDocRequest & { updateUploadProgress: (p: number) => void }) => {
+ const { data } = await axios.post(`${API_ENDPOINTS.branch.getDoc}/`, {
+ ...variables,
+ type: variables.type.title.toLocaleLowerCase()
+ }, {
+ onUploadProgress: (progressEvent) => {
+ variables.updateUploadProgress(progressEvent.progress!);
+ },
+ headers: {
+ "Content-Type": "multipart/form-data"
+ }
+ });
+ return data;
+};
+
+// composable
+
+const useAddDoc = () => {
+ return useMutation({
+ mutationFn: (variables: AddDocRequest & { updateUploadProgress: (p: number) => void }) => handleAddDoc(variables)
+ });
+};
+
+export default useAddDoc;
diff --git a/frontend/composables/api/documents/useDeleteDoc.ts b/frontend/composables/api/documents/useDeleteDoc.ts
new file mode 100644
index 0000000..d241169
--- /dev/null
+++ b/frontend/composables/api/documents/useDeleteDoc.ts
@@ -0,0 +1,27 @@
+// imports
+
+import { useMutation } from "@tanstack/vue-query";
+import axios from "~/configs/axios.config";
+import { API_ENDPOINTS } from "~/constants";
+
+// types
+
+export type DeleteDocRequest = {
+ id: number
+};
+
+// methods
+
+export const handleDeleteDoc = async ({ id }: { id: string | undefined }) => {
+ await axios.delete(`${API_ENDPOINTS.branch.getDoc}/${id}`);
+};
+
+// composable
+
+const useDeleteDoc = (id: Ref) => {
+ return useMutation({
+ mutationFn: () => handleDeleteDoc({ id: id.value })
+ });
+};
+
+export default useDeleteDoc;
diff --git a/frontend/composables/api/documents/useEditDoc.ts b/frontend/composables/api/documents/useEditDoc.ts
new file mode 100644
index 0000000..786962e
--- /dev/null
+++ b/frontend/composables/api/documents/useEditDoc.ts
@@ -0,0 +1,29 @@
+// imports
+
+import { useMutation } from "@tanstack/vue-query";
+import axios from "~/configs/axios.config";
+import { API_ENDPOINTS } from "~/constants";
+
+// types
+
+export type EditDocRequest = {
+ id: number
+};
+
+// methods
+
+export const handleEditDoc = async ({ id, name }: { id: string | undefined, name: string | undefined }) => {
+ await axios.patch(`${API_ENDPOINTS.branch.getDoc}/${id}`, { name });
+};
+
+// composable
+
+const useEditDoc = (id: Ref) => {
+ return useMutation({
+ mutationFn: ({ name }: { name: Ref }) => {
+ return handleEditDoc({ id: id.value, name: name.value });
+ }
+ });
+};
+
+export default useEditDoc;
diff --git a/frontend/composables/api/documents/useGetDoc.ts b/frontend/composables/api/documents/useGetDoc.ts
new file mode 100644
index 0000000..582ab02
--- /dev/null
+++ b/frontend/composables/api/documents/useGetDoc.ts
@@ -0,0 +1,33 @@
+// imports
+
+import { useQuery } from "@tanstack/vue-query";
+import axios from "~/configs/axios.config";
+import { API_ENDPOINTS, QUERY_KEYS } from "~/constants";
+
+// types
+
+export type GetDocResponse = DocumentStructure;
+
+// methods
+
+export const handleGetDoc = async (id : string | undefined) => {
+ const { data } = await axios.get(`${API_ENDPOINTS.branch.getDoc}/${id}`);
+ return data;
+};
+
+// composable
+
+const useGetDoc = (id: ComputedRef) => {
+
+ const enabled = computed(() => {
+ return !!id.value
+ });
+
+ return useQuery({
+ enabled,
+ queryKey: [QUERY_KEYS.document, id],
+ queryFn: () => handleGetDoc(id.value)
+ });
+};
+
+export default useGetDoc;
diff --git a/frontend/composables/api/documents/useMoveDoc.ts b/frontend/composables/api/documents/useMoveDoc.ts
new file mode 100644
index 0000000..91d26ce
--- /dev/null
+++ b/frontend/composables/api/documents/useMoveDoc.ts
@@ -0,0 +1,32 @@
+// imports
+
+import { useMutation } from "@tanstack/vue-query";
+import axios from "~/configs/axios.config";
+import { API_ENDPOINTS } from "~/constants";
+
+// types
+
+export type MoveDocRequest = {
+ itemsToMove: number[] | string[],
+ parent: number | string
+};
+
+// methods
+
+export const handleMoveDoc = async ({ itemsToMove, parent }: MoveDocRequest) => {
+ const apiUrl = `${API_ENDPOINTS.branch.moveDoc}?new_parent_id=${parent}&${itemsToMove.map(i => `patch_list=${i}&`)}`
+ const splittedUrl = apiUrl.split("");
+ splittedUrl.pop()
+
+ await axios.patch(splittedUrl.join("").replaceAll(",", ""));
+};
+
+// composable
+
+const useMoveDoc = () => {
+ return useMutation({
+ mutationFn: (variables: MoveDocRequest) => handleMoveDoc(variables)
+ });
+};
+
+export default useMoveDoc;
diff --git a/frontend/composables/api/documents/useReplyDoc.ts b/frontend/composables/api/documents/useReplyDoc.ts
new file mode 100644
index 0000000..774077d
--- /dev/null
+++ b/frontend/composables/api/documents/useReplyDoc.ts
@@ -0,0 +1,40 @@
+// imports
+
+import { useMutation } from "@tanstack/vue-query";
+import axios from "~/configs/axios.config";
+import { API_ENDPOINTS } from "~/constants";
+
+// types
+
+export type ReplyDocRequest = {
+ user_id: number;
+ message: string;
+ reply_id: number;
+};
+
+export type ReplyDocResponse = {
+ chat_id: number;
+};
+
+// methods
+
+export const handleReplyDoc = async ({ user_id, message, reply_id }: ReplyDocRequest) => {
+ const payload = {
+ user_id,
+ message,
+ item_id: reply_id,
+ };
+
+ const { data } = await axios.post(API_ENDPOINTS.branch.replyDoc, payload);
+ return data;
+};
+
+// composable
+
+const useReplyDoc = () => {
+ return useMutation({
+ mutationFn: (data: ReplyDocRequest) => handleReplyDoc(data),
+ });
+};
+
+export default useReplyDoc;
diff --git a/frontend/composables/api/documents/useSearchFile.ts b/frontend/composables/api/documents/useSearchFile.ts
new file mode 100644
index 0000000..4563efe
--- /dev/null
+++ b/frontend/composables/api/documents/useSearchFile.ts
@@ -0,0 +1,78 @@
+// imports
+
+import { useInfiniteQuery } from "@tanstack/vue-query";
+import axios from "~/configs/axios.config";
+import { API_ENDPOINTS, QUERY_KEYS } from "~/constants";
+import type { ComputedRef } from "vue";
+
+// types
+
+export type SearchFileResponse = Branch;
+
+type HandlerProps = typeof initialPageParam & {
+ signal: AbortSignal,
+ search: string,
+ id: number | undefined;
+ sort: string | undefined;
+}
+
+// state
+
+const initialPageParam = {
+ limit: 10,
+ offset: 0
+};
+
+// methods
+
+export const handleSearchFile = async ({ search, offset, limit, id, signal, sort }: HandlerProps) => {
+ const { data } = await axios.get(`${API_ENDPOINTS.branch.get}/${id}`, {
+ params: {
+ offset,
+ limit,
+ search,
+ sort_by: sort
+ },
+ signal
+ });
+ return data;
+};
+
+// composable
+
+const useSearchFile = (search: Ref, id: Ref, sort: ComputedRef) => {
+
+ const enabled = computed(() => {
+ return search.value.trim() != "" && !!id.value;
+ });
+
+ return useInfiniteQuery({
+ enabled,
+ retry: false,
+ refetchOnMount: false,
+ refetchOnWindowFocus: false,
+ queryKey: [QUERY_KEYS.searchFile, search, id, sort],
+ queryFn: ({ pageParam, signal }) => handleSearchFile({
+ ...pageParam,
+ signal,
+ search: search.value,
+ sort: sort.value,
+ id: id.value
+ }),
+ initialPageParam,
+ getNextPageParam: (lastPage, pages) => {
+ const page = pages.length + 1;
+
+ const limit = initialPageParam.limit;
+
+ const nextPageParams = {
+ offset: page * limit - limit,
+ limit
+ };
+
+ return lastPage?.structure.next ? nextPageParams : undefined;
+ }
+ });
+};
+
+export default useSearchFile;
\ No newline at end of file
diff --git a/frontend/composables/useImageColor.ts b/frontend/composables/useImageColor.ts
new file mode 100644
index 0000000..11c88e6
--- /dev/null
+++ b/frontend/composables/useImageColor.ts
@@ -0,0 +1,32 @@
+import type { FastAverageColorResult } from "fast-average-color";
+import { FastAverageColor } from "fast-average-color";
+
+export const useImageColor = (img: string) => {
+ const fac = new FastAverageColor();
+ const colorObject = ref();
+ const isPending = ref(false);
+
+ const extractImageColor = async () => {
+ isPending.value = true;
+
+ const imageEl = document.querySelector(img) as HTMLImageElement;
+
+ try {
+ const color = await fac.getColorAsync(imageEl);
+ isPending.value = false;
+ colorObject.value = color;
+ } catch (e) {
+ isPending.value = false;
+ }
+ };
+
+ onMounted(() => {
+ extractImageColor();
+ });
+
+ return {
+ colorObject,
+ extractImageColor,
+ isPending
+ };
+};
\ No newline at end of file
diff --git a/frontend/composables/useToast.ts b/frontend/composables/useToast.ts
index 95bec80..4649bac 100644
--- a/frontend/composables/useToast.ts
+++ b/frontend/composables/useToast.ts
@@ -1,23 +1,22 @@
+export type ToastOptions = {
+ description?: string;
+ duration?: number;
+ status?: "success" | "error" | "info" | "warning",
+}
+
type Toast = {
id: number;
message: string;
- description?: string;
- duration?: number;
-}
-
-type Props = {
- message: string,
- description?: string,
- options?: Omit
+ options?: ToastOptions
}
const toasts = ref([]);
export function useToast() {
- const addToast = ({ message, description, options = {} }: Props) => {
+ const addToast = ({ message, options = {} }: Omit) => {
const id = Date.now();
- toasts.value.push({ id, message, description, ...options });
+ toasts.value.push({ id, message, options });
};
const destroyToast = (id: number) => {
diff --git a/frontend/constants/index.ts b/frontend/constants/index.ts
index 51d3b72..43c7d1d 100644
--- a/frontend/constants/index.ts
+++ b/frontend/constants/index.ts
@@ -1,90 +1,26 @@
export const API_ENDPOINTS = {
- account : {
- send_otp : "/accounts/send_otp",
+ account: {
+ send_otp: "/accounts/send_otp",
},
auth: {
signin: "/token",
logout: "/accounts/logout",
- }
+ },
+ chat: {
+ messages: "/chat/product",
+ new_message: "/chat/product",
+ },
};
export const QUERY_KEYS = {
-
+ chat: "chat",
};
-export const FILE_FORMATS = [
- {
- ext: [".jpg", ".jpeg", ".png", ".svg", ".bmp", ".webp", ".gif", ".tiff", ".heif", ".raw"],
- icon: "bi:file-earmark-image",
- },
- {
- ext: [".mp4", ".mkv", ".avi", ".mov", ".wmv", ".flv", ".webm", ".mpeg", ".3gp", ".mts"],
- icon: "bi:file-earmark-play",
- },
- {
- ext: [".zip", ".rar", ".tar.gz", ".dmg", ".7z", ".bz2", ".tar", ".gz", ".xz"],
- icon: "bi:file-earmark-zip",
- },
- {
- ext: [".mp3", ".wav", ".aac", ".flac", ".ogg", ".wma", ".alac", ".m4a", ".opus", ".aiff"],
- icon: "bi:file-earmark-music",
- },
- {
- ext: [
- ".py",
- ".js",
- ".java",
- ".cpp",
- ".c",
- ".html",
- ".css",
- ".php",
- ".rb",
- ".swift",
- ".go",
- ".sh",
- ".md",
- ".rust",
- ".pl",
- ],
- icon: "bi:file-earmark-code",
- },
- {
- ext: [
- ".json",
- ".xml",
- ".sql",
- ".csv",
- ".xls",
- ".xlsx",
- ".avro",
- ".hdf5",
- ".yaml",
- ".tsv",
- ".ods",
- ".db",
- ".sqlite",
- ],
- icon: "bi:file-earmark-spreadsheet",
- },
- {
- ext: [".pdf", ".epub", ".xps", ".djvu", ".cbz", ".cbt"],
- icon: "bi:file-earmark-pdf",
- },
- {
- ext: [".ppt", ".pptx", ".odp", ".pps", ".ppsx", ".key"],
- icon: "bi:file-earmark-slides",
- },
- {
- ext: [".txt", ".doc", ".docx", ".odt", ".rtf", ".wps", ".wpd"],
- icon: "bi:file-earmark-text",
- },
- {
- ext: [".lock", ".lck"],
- icon: "bi:file-earmark-lock",
- },
- {
- ext: [".exe", ".bin", ".elf", ".dll", ".iso", ".dmg", ".swf", ".o", ".obg", ".pe", ".app"],
- icon: "bi:file-earmark-binary",
- },
-];
\ No newline at end of file
+export const MUTATION_KEYS = {
+ create_chat: "create_chat",
+};
+
+export const PRODUCT_RANGE = {
+ min: 0,
+ max: 100000,
+};
diff --git a/frontend/nuxt.config.ts b/frontend/nuxt.config.ts
index d863918..8978648 100644
--- a/frontend/nuxt.config.ts
+++ b/frontend/nuxt.config.ts
@@ -43,11 +43,12 @@ export default defineNuxtConfig({
],
"@nuxt/icon",
"reka-ui/nuxt",
+ "@vueuse/nuxt",
],
runtimeConfig: {
public: {
- API_BASE_URL: "http://38.60.202.91:8000",
+ API_BASE_URL: "http://38.60.202.91:8001",
},
},
});
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 76a2eee..80ba4c0 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -13,7 +13,9 @@
"@tanstack/vue-query-devtools": "^5.62.3",
"@vuelidate/core": "^2.0.3",
"@vuelidate/validators": "^2.0.4",
+ "@vueuse/nuxt": "^12.3.0",
"axios": "^1.7.9",
+ "fast-average-color": "^9.4.0",
"gsap": "^3.12.5",
"nuxt": "^3.14.1592",
"reka-ui": "^1.0.0-alpha.6",
@@ -3399,14 +3401,14 @@
}
},
"node_modules/@vueuse/core": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.0.0.tgz",
- "integrity": "sha512-C12RukhXiJCbx4MGhjmd/gH52TjJsc3G0E0kQj/kb19H3Nt6n1CA4DRWuTdWWcaFRdlTe0npWDS942mvacvNBw==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.3.0.tgz",
+ "integrity": "sha512-cnV8QDKZrsyKC7tWjPbeEUz2cD9sa9faxF2YkR8QqNwfofgbOhmfIgvSYmkp+ttSvfOw4E6hLcQx15mRPr0yBA==",
"license": "MIT",
"dependencies": {
"@types/web-bluetooth": "^0.0.20",
- "@vueuse/metadata": "12.0.0",
- "@vueuse/shared": "12.0.0",
+ "@vueuse/metadata": "12.3.0",
+ "@vueuse/shared": "12.3.0",
"vue": "^3.5.13"
},
"funding": {
@@ -3414,18 +3416,98 @@
}
},
"node_modules/@vueuse/metadata": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.0.0.tgz",
- "integrity": "sha512-Yzimd1D3sjxTDOlF05HekU5aSGdKjxhuhRFHA7gDWLn57PRbBIh+SF5NmjhJ0WRgF3my7T8LBucyxdFJjIfRJQ==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.3.0.tgz",
+ "integrity": "sha512-M/iQHHjMffOv2npsw2ihlUx1CTiBwPEgb7DzByLq7zpg1+Ke8r7s9p5ybUWc5OIeGewtpY4Xy0R2cKqFqM8hFg==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
+ "node_modules/@vueuse/nuxt": {
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/nuxt/-/nuxt-12.3.0.tgz",
+ "integrity": "sha512-xlpYIroHvdrwyZRHvXKekdFLH0IIPaOLKkt8VcVFZLHC3CgPiiwqGDK2Uvea8Hb51zhTWodYpd5Y2jCcsjZmBw==",
+ "license": "MIT",
+ "dependencies": {
+ "@nuxt/kit": "^3.15.0",
+ "@vueuse/core": "12.3.0",
+ "@vueuse/metadata": "12.3.0",
+ "local-pkg": "^0.5.1",
+ "vue": "^3.5.13"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "nuxt": "^3.0.0"
+ }
+ },
+ "node_modules/@vueuse/nuxt/node_modules/@nuxt/kit": {
+ "version": "3.15.1",
+ "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.15.1.tgz",
+ "integrity": "sha512-7cVWjzfz3L6CsZrg6ppDZa7zGrZxCSfZjEQDIvVFn4mFKtJlK9k2izf5EewL6luzWwIQojkZAC3iq/1wtgI0Xw==",
+ "license": "MIT",
+ "dependencies": {
+ "@nuxt/schema": "3.15.1",
+ "c12": "^2.0.1",
+ "consola": "^3.3.3",
+ "defu": "^6.1.4",
+ "destr": "^2.0.3",
+ "globby": "^14.0.2",
+ "ignore": "^7.0.0",
+ "jiti": "^2.4.2",
+ "klona": "^2.0.6",
+ "knitwork": "^1.2.0",
+ "mlly": "^1.7.3",
+ "ohash": "^1.1.4",
+ "pathe": "^2.0.0",
+ "pkg-types": "^1.3.0",
+ "scule": "^1.3.0",
+ "semver": "^7.6.3",
+ "ufo": "^1.5.4",
+ "unctx": "^2.4.1",
+ "unimport": "^3.14.5",
+ "untyped": "^1.5.2"
+ },
+ "engines": {
+ "node": ">=18.20.5"
+ }
+ },
+ "node_modules/@vueuse/nuxt/node_modules/@nuxt/schema": {
+ "version": "3.15.1",
+ "resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-3.15.1.tgz",
+ "integrity": "sha512-n5kOHt8uUyUM9z4Wu/8tIZkBYh3KTCGvyruG6oD9bfeT4OaS21+X3M7XsTXFMe+eYBZA70IFFlWn1JJZIPsKeA==",
+ "license": "MIT",
+ "dependencies": {
+ "consola": "^3.3.3",
+ "defu": "^6.1.4",
+ "pathe": "^2.0.0",
+ "std-env": "^3.8.0"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.10.0"
+ }
+ },
+ "node_modules/@vueuse/nuxt/node_modules/ignore": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.0.tgz",
+ "integrity": "sha512-lcX8PNQygAa22u/0BysEY8VhaFRzlOkvdlKczDPnJvrkJD1EuqzEky5VYYKM2iySIuaVIDv9N190DfSreSLw2A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/@vueuse/nuxt/node_modules/pathe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.0.tgz",
+ "integrity": "sha512-G7n4uhtk9qJt2hlD+UFfsIGY854wpF+zs2bUbQ3CQEUTcn7v25LRsrmurOxTo4bJgjE4qkyshd9ldsEuY9M6xg==",
+ "license": "MIT"
+ },
"node_modules/@vueuse/shared": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.0.0.tgz",
- "integrity": "sha512-3i6qtcq2PIio5i/vVYidkkcgvmTjCqrf26u+Fd4LhnbBmIT6FN8y6q/GJERp8lfcB9zVEfjdV0Br0443qZuJpw==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.3.0.tgz",
+ "integrity": "sha512-X3YD35GUeW0d5Gajcwv9jdLAJTV2Jdb/Ll6Ii2JIYcKLYZqv5wxyLeKtiQkqWmHg3v0J0ZWjDUMVOw2E7RCXfA==",
"license": "MIT",
"dependencies": {
"vue": "^3.5.13"
@@ -4372,9 +4454,9 @@
"license": "MIT"
},
"node_modules/consola": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz",
- "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==",
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/consola/-/consola-3.3.3.tgz",
+ "integrity": "sha512-Qil5KwghMzlqd51UXM0b6fyaGHtOC22scxrwrz4A2882LyUMwQjnvaedN1HAeXzphspQ6CpHkzMAWxBTUruDLg==",
"license": "MIT",
"engines": {
"node": "^14.18.0 || >=16.10.0"
@@ -5162,6 +5244,15 @@
"ufo": "^1.1.2"
}
},
+ "node_modules/fast-average-color": {
+ "version": "9.4.0",
+ "resolved": "https://registry.npmjs.org/fast-average-color/-/fast-average-color-9.4.0.tgz",
+ "integrity": "sha512-bvM8vV6YwK07dPbzFz77zJaBcfF6ABVfgNwaxVgXc2G+o0e/tzLCF9WU8Ryp1r0Nkk6JuJNsWCzbb4cLOMlB+Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -6107,9 +6198,9 @@
}
},
"node_modules/jiti": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.1.tgz",
- "integrity": "sha512-yPBThwecp1wS9DmoA4x4KR2h3QoslacnDR8ypuFM962kI4/456Iy1oHx2RAgh4jfZNdn0bctsdadceiBUgpU1g==",
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
+ "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==",
"license": "MIT",
"bin": {
"jiti": "lib/jiti-cli.mjs"
@@ -6203,9 +6294,9 @@
}
},
"node_modules/knitwork": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/knitwork/-/knitwork-1.1.0.tgz",
- "integrity": "sha512-oHnmiBUVHz1V+URE77PNot2lv3QiYU2zQf1JjOVkMt3YDKGbu8NAFr+c4mcNOhdsGrB/VpVbRwPwhiXrPhxQbw==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/knitwork/-/knitwork-1.2.0.tgz",
+ "integrity": "sha512-xYSH7AvuQ6nXkq42x0v5S8/Iry+cfulBz/DJQzhIyESdLD7425jXsPy4vn5cCXU+HhRN2kVw51Vd1K6/By4BQg==",
"license": "MIT"
},
"node_modules/kolorist": {
@@ -6622,9 +6713,9 @@
}
},
"node_modules/magic-string": {
- "version": "0.30.14",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz",
- "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==",
+ "version": "0.30.17",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
+ "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0"
@@ -7655,13 +7746,13 @@
}
},
"node_modules/pkg-types": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.1.tgz",
- "integrity": "sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.0.tgz",
+ "integrity": "sha512-kS7yWjVFCkIw9hqdJBoMxDdzEngmkr5FXeWZZfQ6GoYacjVnsW6l2CcYW/0ThD0vF4LPJgVYnrg4d0uuhwYQbg==",
"license": "MIT",
"dependencies": {
"confbox": "^0.1.8",
- "mlly": "^1.7.2",
+ "mlly": "^1.7.3",
"pathe": "^1.1.2"
}
},
@@ -9270,15 +9361,28 @@
"license": "MIT"
},
"node_modules/unctx": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/unctx/-/unctx-2.3.1.tgz",
- "integrity": "sha512-PhKke8ZYauiqh3FEMVNm7ljvzQiph0Mt3GBRve03IJm7ukfaON2OBK795tLwhbyfzknuRRkW0+Ze+CQUmzOZ+A==",
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/unctx/-/unctx-2.4.1.tgz",
+ "integrity": "sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==",
"license": "MIT",
"dependencies": {
- "acorn": "^8.8.2",
+ "acorn": "^8.14.0",
"estree-walker": "^3.0.3",
- "magic-string": "^0.30.0",
- "unplugin": "^1.3.1"
+ "magic-string": "^0.30.17",
+ "unplugin": "^2.1.0"
+ }
+ },
+ "node_modules/unctx/node_modules/unplugin": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.1.2.tgz",
+ "integrity": "sha512-Q3LU0e4zxKfRko1wMV2HmP8lB9KWislY7hxXpxd+lGx0PRInE4vhMBVEZwpdVYHvtqzhSrzuIfErsob6bQfCzw==",
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.14.0",
+ "webpack-virtual-modules": "^0.6.2"
+ },
+ "engines": {
+ "node": ">=18.12.0"
}
},
"node_modules/undici-types": {
@@ -9340,15 +9444,16 @@
}
},
"node_modules/unimport": {
- "version": "3.14.3",
- "resolved": "https://registry.npmjs.org/unimport/-/unimport-3.14.3.tgz",
- "integrity": "sha512-yEJps4GW7jBdoQlxEV0ElBCJsJmH8FdZtk4oog0y++8hgLh0dGnDpE4oaTc0Lfx4N5rRJiGFUWHrBqC8CyUBmQ==",
+ "version": "3.14.5",
+ "resolved": "https://registry.npmjs.org/unimport/-/unimport-3.14.5.tgz",
+ "integrity": "sha512-tn890SwFFZxqaJSKQPPd+yygfKSATbM8BZWW1aCR2TJBTs1SDrmLamBueaFtYsGjHtQaRgqEbQflOjN2iW12gA==",
"license": "MIT",
"dependencies": {
"@rollup/pluginutils": "^5.1.3",
"acorn": "^8.14.0",
"escape-string-regexp": "^5.0.0",
"estree-walker": "^3.0.3",
+ "fast-glob": "^3.3.2",
"local-pkg": "^0.5.1",
"magic-string": "^0.30.14",
"mlly": "^1.7.3",
@@ -9357,7 +9462,6 @@
"pkg-types": "^1.2.1",
"scule": "^1.3.0",
"strip-literal": "^2.1.1",
- "tinyglobby": "^0.2.10",
"unplugin": "^1.16.0"
}
},
@@ -9617,17 +9721,18 @@
}
},
"node_modules/untyped": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/untyped/-/untyped-1.5.1.tgz",
- "integrity": "sha512-reBOnkJBFfBZ8pCKaeHgfZLcehXtM6UTxc+vqs1JvCps0c4amLNp3fhdGBZwYp+VLyoY9n3X5KOP7lCyWBUX9A==",
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/untyped/-/untyped-1.5.2.tgz",
+ "integrity": "sha512-eL/8PlhLcMmlMDtNPKhyyz9kEBDS3Uk4yMu/ewlkT2WFbtzScjHWPJLdQLmaGPUKjXzwe9MumOtOgc4Fro96Kg==",
"license": "MIT",
"dependencies": {
- "@babel/core": "^7.25.7",
- "@babel/standalone": "^7.25.7",
- "@babel/types": "^7.25.7",
+ "@babel/core": "^7.26.0",
+ "@babel/standalone": "^7.26.4",
+ "@babel/types": "^7.26.3",
+ "citty": "^0.1.6",
"defu": "^6.1.4",
- "jiti": "^2.3.1",
- "mri": "^1.2.0",
+ "jiti": "^2.4.1",
+ "knitwork": "^1.2.0",
"scule": "^1.3.0"
},
"bin": {
diff --git a/frontend/package.json b/frontend/package.json
index f1154d8..ffe836a 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -18,7 +18,9 @@
"@tanstack/vue-query-devtools": "^5.62.3",
"@vuelidate/core": "^2.0.3",
"@vuelidate/validators": "^2.0.4",
+ "@vueuse/nuxt": "^12.3.0",
"axios": "^1.7.9",
+ "fast-average-color": "^9.4.0",
"gsap": "^3.12.5",
"nuxt": "^3.14.1592",
"reka-ui": "^1.0.0-alpha.6",
diff --git a/frontend/pages/category/index.vue b/frontend/pages/category/index.vue
new file mode 100644
index 0000000..9fa1104
--- /dev/null
+++ b/frontend/pages/category/index.vue
@@ -0,0 +1,68 @@
+
+
+
+ دسته بندی ها
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/pages/product/[id].vue b/frontend/pages/product/[id].vue
index 056cfac..8d4d78a 100644
--- a/frontend/pages/product/[id].vue
+++ b/frontend/pages/product/[id].vue
@@ -1,4 +1,6 @@
-
+
diff --git a/frontend/pages/products.vue b/frontend/pages/products.vue
index e8e68c0..80985b8 100644
--- a/frontend/pages/products.vue
+++ b/frontend/pages/products.vue
@@ -1,20 +1,46 @@
-
+
-
-
-
+
+
+
همه محصولات
-
+
+
+
+
diff --git a/frontend/pages/signin/index.vue b/frontend/pages/signin/index.vue
index 73d33f8..33f65fb 100644
--- a/frontend/pages/signin/index.vue
+++ b/frontend/pages/signin/index.vue
@@ -57,12 +57,22 @@ const sendOtpHandler = async () => {
phone: `0${loginInfo.value.phone}`
});
- addToast({ message: "کد برای شما ارسال شد" });
+ addToast({
+ message: "کد برای شما ارسال شد",
+ options: {
+ status: "success"
+ }
+ });
showOtp.value = true;
} catch (e) {
- addToast({ message: "مشکلی پیش آمده" });
+ addToast({
+ message: "مشکلی پیش آمده",
+ options: {
+ status: "error"
+ }
+ });
}
}
};
diff --git a/frontend/plugins/gsap.client.ts b/frontend/plugins/gsap.client.ts
index e23323b..328cba3 100644
--- a/frontend/plugins/gsap.client.ts
+++ b/frontend/plugins/gsap.client.ts
@@ -1,10 +1,11 @@
import { gsap } from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
import { ScrollToPlugin } from 'gsap/ScrollToPlugin'
+import { TextPlugin } from "gsap/TextPlugin";
export default defineNuxtPlugin(() => {
if (process.client) {
- gsap.registerPlugin(ScrollTrigger, ScrollToPlugin)
+ gsap.registerPlugin(ScrollTrigger, ScrollToPlugin, TextPlugin)
}
return {
diff --git a/frontend/public/icons/filter-list.svg b/frontend/public/icons/filter-list.svg
new file mode 100644
index 0000000..92bed82
--- /dev/null
+++ b/frontend/public/icons/filter-list.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/frontend/public/img/ai-loading-2.gif b/frontend/public/img/ai-loading-2.gif
new file mode 100644
index 0000000..d2242eb
Binary files /dev/null and b/frontend/public/img/ai-loading-2.gif differ
diff --git a/frontend/public/img/ai-loading.gif b/frontend/public/img/ai-loading.gif
new file mode 100644
index 0000000..70f2fb1
Binary files /dev/null and b/frontend/public/img/ai-loading.gif differ
diff --git a/frontend/public/img/product-4.jpg b/frontend/public/img/product-4.jpg
new file mode 100644
index 0000000..1d92658
Binary files /dev/null and b/frontend/public/img/product-4.jpg differ
diff --git a/frontend/public/img/product-5.jpg b/frontend/public/img/product-5.jpg
new file mode 100644
index 0000000..2cacba8
Binary files /dev/null and b/frontend/public/img/product-5.jpg differ
diff --git a/frontend/public/img/test1.jpg b/frontend/public/img/test1.jpg
new file mode 100644
index 0000000..a09bb75
Binary files /dev/null and b/frontend/public/img/test1.jpg differ
diff --git a/frontend/types/global.d.ts b/frontend/types/global.d.ts
index bc70bd1..f0df3d0 100644
--- a/frontend/types/global.d.ts
+++ b/frontend/types/global.d.ts
@@ -7,4 +7,11 @@ declare global {
previous: string | null;
results: T[];
};
+
+ type Chat = {
+ id: number,
+ sender: "ai" | "user",
+ content: string
+ }
+
}