Merge branch 'main' of https://github.com/Byeto-Company/hossein_por_shop
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
// types
|
||||
|
||||
type Props = {
|
||||
@@ -16,18 +15,14 @@ defineProps<Props>();
|
||||
|
||||
// state
|
||||
|
||||
const params : any = inject("params");
|
||||
const params: any = inject("params");
|
||||
|
||||
const page = ref(params?.page ? Number(params.page) : 1);
|
||||
// computed
|
||||
|
||||
// watch
|
||||
|
||||
watch(
|
||||
() => page.value,
|
||||
(newPage) => {
|
||||
params.page = newPage;
|
||||
}
|
||||
);
|
||||
const page = computed({
|
||||
get: () => (params?.page ? Number(params.page) : 1),
|
||||
set: (value: number) => (params.page = value),
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -47,7 +42,11 @@ watch(
|
||||
<PaginationNext
|
||||
class="w-9 h-9 ml-4 flex items-center justify-center cursor-pointer hover:bg-slate-100 transition disabled:opacity-50 disabled:cursor-not-allowed rounded-lg"
|
||||
>
|
||||
<Icon name="ci:chevron-right" class="**:fill-back" size="18px" />
|
||||
<Icon
|
||||
name="ci:chevron-right"
|
||||
class="**:fill-back"
|
||||
size="18px"
|
||||
/>
|
||||
</PaginationNext>
|
||||
|
||||
<template v-for="(page, index) in items">
|
||||
|
||||
@@ -13,7 +13,7 @@ defineProps<Props>();
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="w-full flex-col flex-grow py-[12rem] gap-6 border-2 border-slate-200 border-dashed size-full rounded-100 flex-center"
|
||||
class="w-full flex-col flex-grow py-[12rem] gap-6 border-2 border-slate-200 border-dashed size-full rounded-xl flex-center"
|
||||
>
|
||||
<Icon :name="icon" size="50" class="**:fill-gray-500" />
|
||||
<span class="text-lg text-gray-500"> {{ title }} </span>
|
||||
|
||||
@@ -56,13 +56,23 @@ await suspense();
|
||||
{{ `${account?.first_name} ${account?.last_name}` }}
|
||||
</p>
|
||||
</span>
|
||||
<button class="text-xs font-semibold text-cyan-500">
|
||||
<NuxtLink
|
||||
:to="{ name: 'profile' }"
|
||||
class="text-xs font-semibold text-cyan-500"
|
||||
>
|
||||
ویرایش اطلاعات
|
||||
</button>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<img
|
||||
src="https://shatelpart.com/storage/users/user-15-155Mn1.png"
|
||||
class="rounded-full size-[3rem] hover:border-dynamic-rose transition"
|
||||
<Avatar
|
||||
class="!size-[3rem]"
|
||||
:src="account!.profile_photo"
|
||||
:alt="
|
||||
account?.first_name && account?.last_name
|
||||
? `${account?.first_name.charAt(
|
||||
0
|
||||
)} ${account?.last_name.charAt(0)}`
|
||||
: 'بدون نام کاربری'
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
<script setup lang="ts"></script>
|
||||
<script setup lang="ts">
|
||||
// types
|
||||
|
||||
type Props = {
|
||||
data: Ticket;
|
||||
};
|
||||
|
||||
// props
|
||||
|
||||
defineProps<Props>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<tr
|
||||
@@ -8,13 +18,15 @@
|
||||
scope="row"
|
||||
class="w-3/12 px-6 py-6 font-medium whitespace-nowrap text-black"
|
||||
>
|
||||
Apple MacBook Pro 17
|
||||
{{ data.ticket_category }}
|
||||
</td>
|
||||
<td class="w-3/12 px-6 py-6">Silver</td>
|
||||
<td class="w-3/12 px-6 py-6">Laptop</td>
|
||||
<td class="w-2/12 px-6 py-6">$2999</td>
|
||||
<td class="w-3/12 px-6 py-6">{{ data.subject }}</td>
|
||||
<td class="w-3/12 px-6 py-6">{{ data.created_at }}</td>
|
||||
<td class="w-2/12 px-6 py-6">{{ data.status }}</td>
|
||||
<td class="w-1/12 px-6 py-6">
|
||||
<NuxtLink :to="{ name: 'profile-tickets-id', params: { id: 1 } }">
|
||||
<NuxtLink
|
||||
:to="{ name: 'profile-tickets-id', params: { id: data.id } }"
|
||||
>
|
||||
<button
|
||||
class="size-10 flex-center border border-slate-200 rounded-md"
|
||||
>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<tr
|
||||
class="odd:bg-white even:bg-gray-50 last:border-none border-b border-slate-200"
|
||||
>
|
||||
<td
|
||||
scope="row"
|
||||
class="w-3/12 px-6 py-6 font-medium whitespace-nowrap text-black"
|
||||
>
|
||||
<Skeleton class="w-full !h-10 !rounded-sm" />
|
||||
</td>
|
||||
<td class="w-3/12 px-6 py-6">
|
||||
<Skeleton class="w-full !h-10 !rounded-sm" />
|
||||
</td>
|
||||
<td class="w-3/12 px-6 py-6">
|
||||
<Skeleton class="w-full !h-10 !rounded-sm" />
|
||||
</td>
|
||||
<td class="w-2/12 px-6 py-6">
|
||||
<Skeleton class="w-full !h-10 !rounded-sm" />
|
||||
</td>
|
||||
<td class="w-1/12 px-6 py-6">
|
||||
<Skeleton class="!size-10 !rounded-sm" />
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -11,13 +11,11 @@ export type SignInRequest = {
|
||||
};
|
||||
|
||||
export type SignInResponse = {
|
||||
access: string,
|
||||
refresh: string,
|
||||
access: string;
|
||||
refresh: string;
|
||||
};
|
||||
|
||||
|
||||
const useSignIn = () => {
|
||||
|
||||
// state
|
||||
|
||||
const { $axios: axios } = useNuxtApp();
|
||||
@@ -25,12 +23,15 @@ const useSignIn = () => {
|
||||
// methods
|
||||
|
||||
const handleSignIn = async (variables: SignInRequest) => {
|
||||
const { data } = await axios.post<SignInResponse>(`${API_ENDPOINTS.auth.signin}/`, variables);
|
||||
const { data } = await axios.post<SignInResponse>(
|
||||
`${API_ENDPOINTS.auth.signin}`,
|
||||
variables
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (variables: SignInRequest) => handleSignIn(variables)
|
||||
mutationFn: (variables: SignInRequest) => handleSignIn(variables),
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// imports
|
||||
|
||||
import { useQuery } from "@tanstack/vue-query";
|
||||
import { API_ENDPOINTS, QUERY_KEYS } from "~/constants";
|
||||
|
||||
// types
|
||||
|
||||
export type GetAllTicketsResponse = ApiPaginated<Ticket>;
|
||||
|
||||
export type GetAllTicketsFilters = {
|
||||
sort: string | undefined;
|
||||
filter: string | undefined;
|
||||
page: string | string[];
|
||||
};
|
||||
|
||||
const useGetAllTickets = (params: Ref<GetAllTicketsFilters>) => {
|
||||
// state
|
||||
|
||||
const { $axios: axios } = useNuxtApp();
|
||||
|
||||
// methods
|
||||
|
||||
const handleGetAllTickets = async (params: GetAllTicketsFilters) => {
|
||||
const { data } = await axios.get<GetAllTicketsResponse>(
|
||||
API_ENDPOINTS.tickets.get_all,
|
||||
{
|
||||
params: {
|
||||
sort: params.sort,
|
||||
filter: params.filter,
|
||||
offset: Number(params.page) * 10 - 10,
|
||||
limit: 10,
|
||||
},
|
||||
}
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
return useQuery({
|
||||
queryKey: [QUERY_KEYS.tickets, params],
|
||||
queryFn: () => handleGetAllTickets(params.value),
|
||||
});
|
||||
};
|
||||
|
||||
export default useGetAllTickets;
|
||||
@@ -34,6 +34,9 @@ export const API_ENDPOINTS = {
|
||||
get_all: "/products",
|
||||
categories: "/products/categories",
|
||||
},
|
||||
tickets: {
|
||||
get_all: "/tickets/",
|
||||
},
|
||||
};
|
||||
|
||||
export const QUERY_KEYS = {
|
||||
@@ -47,6 +50,7 @@ export const QUERY_KEYS = {
|
||||
account: "account",
|
||||
categories: "categories",
|
||||
addresses: "addresses",
|
||||
tickets: "tickets",
|
||||
};
|
||||
|
||||
export const MUTATION_KEYS = {
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
// imports
|
||||
|
||||
import useGetAllTickets, {
|
||||
type GetAllTicketsFilters,
|
||||
} from "~/composables/api/tickets/useGetAllTickets";
|
||||
|
||||
// meta
|
||||
|
||||
definePageMeta({
|
||||
@@ -8,10 +14,12 @@ definePageMeta({
|
||||
|
||||
// state
|
||||
|
||||
const filters = ref({
|
||||
const params = useUrlSearchParams();
|
||||
|
||||
const filters = ref<GetAllTicketsFilters>({
|
||||
sort: undefined,
|
||||
status: undefined,
|
||||
search: "",
|
||||
filter: undefined,
|
||||
page: params.page ?? 1,
|
||||
});
|
||||
|
||||
const tableHeads = ref([
|
||||
@@ -21,6 +29,22 @@ const tableHeads = ref([
|
||||
"وضعیت",
|
||||
"عملیات",
|
||||
]);
|
||||
|
||||
// queries
|
||||
|
||||
const { data, isLoading: ticketsIsLoading } = useGetAllTickets(filters);
|
||||
|
||||
// computed
|
||||
|
||||
const tickets = computed(() => {
|
||||
return data.value?.results.flat();
|
||||
});
|
||||
|
||||
const paginationData = computed(() => {
|
||||
return tickets!.value?.results.map((_, i: number) => {
|
||||
return { type: "page", value: i };
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -47,7 +71,7 @@ const tableHeads = ref([
|
||||
'در حال پردازش',
|
||||
'لغو شده',
|
||||
]"
|
||||
v-model="filters.status!"
|
||||
v-model="filters.filter!"
|
||||
triggerRootClass="!py-2.5"
|
||||
class="w-[5rem]"
|
||||
/>
|
||||
@@ -63,7 +87,14 @@ const tableHeads = ref([
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
<Table>
|
||||
<Placeholder
|
||||
v-if="!tickets?.length && !ticketsIsLoading"
|
||||
class="!w-full !py-[5rem]"
|
||||
icon="bi:ticket"
|
||||
title="تیکتی یافت نشد"
|
||||
/>
|
||||
|
||||
<Table v-else>
|
||||
<template #thead>
|
||||
<th
|
||||
v-for="(tableHead, index) in tableHeads"
|
||||
@@ -82,9 +113,22 @@ const tableHeads = ref([
|
||||
</th>
|
||||
</template>
|
||||
<template #tbody>
|
||||
<TicketsTableRow v-for="i in 4" />
|
||||
<template v-if="ticketsIsLoading">
|
||||
<TicketsTableRowLoading v-for="i in 5" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<TicketsTableRow
|
||||
v-for="(ticket, index) in tickets"
|
||||
:key="index"
|
||||
:data="ticket"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
</Table>
|
||||
|
||||
<div v-if="tickets?.length > 10" class="w-full flex-center py-10">
|
||||
<Pagination :items="paginationData" :total="data?.count" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Vendored
+9
@@ -165,4 +165,13 @@ declare global {
|
||||
iconClass?: string;
|
||||
onClick?: () => void;
|
||||
};
|
||||
|
||||
type Ticket = {
|
||||
id: number;
|
||||
subject: string;
|
||||
ticket_category: string;
|
||||
status: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user