diff --git a/src/features/users/lib/api.ts b/src/features/users/lib/api.ts index 9e0c1ee..bef8265 100644 --- a/src/features/users/lib/api.ts +++ b/src/features/users/lib/api.ts @@ -43,4 +43,15 @@ export const user_api = { const res = await httpClient.post(API_URLS.PasswordSet(id), body); return res; }, + + async price_type_set({ + body, + id, + }: { + id: string | number; + body: { ids: number[] }; + }) { + const res = await httpClient.post(API_URLS.PriceTypeSet(id), body); + return res; + }, }; diff --git a/src/features/users/lib/data.ts b/src/features/users/lib/data.ts index cf8ce97..b1bf28c 100644 --- a/src/features/users/lib/data.ts +++ b/src/features/users/lib/data.ts @@ -6,6 +6,7 @@ export interface UserData { short_name: string; created_at: string; password_set: boolean; + price_types: number[]; } export interface UserListRes { diff --git a/src/features/users/ui/UserCard.tsx b/src/features/users/ui/UserCard.tsx index 48f2b17..201445f 100644 --- a/src/features/users/ui/UserCard.tsx +++ b/src/features/users/ui/UserCard.tsx @@ -1,9 +1,18 @@ "use client"; +import price_type_api from "@/features/price-type/lib/api"; import { user_api } from "@/features/users/lib/api"; import type { UserData } from "@/features/users/lib/data"; import formatDate from "@/shared/lib/formatDate"; +import { cn } from "@/shared/lib/utils"; import { Button } from "@/shared/ui/button"; +import { + Command, + CommandEmpty, + CommandGroup, + CommandItem, + CommandList, +} from "@/shared/ui/command"; import { Dialog, DialogContent, @@ -19,6 +28,7 @@ import { } from "@/shared/ui/form"; import { Input } from "@/shared/ui/input"; import { Label } from "@/shared/ui/label"; +import { Popover, PopoverContent, PopoverTrigger } from "@/shared/ui/popover"; import { Table, TableBody, @@ -28,10 +38,10 @@ import { TableRow, } from "@/shared/ui/table"; import { zodResolver } from "@hookform/resolvers/zod"; -import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import type { AxiosError } from "axios"; -import { Edit } from "lucide-react"; -import { useState } from "react"; +import { Check, ChevronsUpDown, Edit } from "lucide-react"; +import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import z from "zod"; @@ -49,7 +59,28 @@ interface UserListProps { export function UserCard({ users }: UserListProps) { const [edit, setEdit] = useState(null); const [open, setOpen] = useState(false); + const [openPriceId, setOpenPriceId] = useState(null); const queryClient = useQueryClient(); + const [values, setValues] = useState>({}); + + const { data } = useQuery({ + queryKey: ["price_type"], + queryFn: () => price_type_api.list(), + select(data) { + return data.data; + }, + }); + + useEffect(() => { + const initialValues: Record = {}; + users.forEach((user) => { + if (user.price_types) { + initialValues[user.id] = user.price_types.map((id) => id.toString()); + } + }); + + setValues(initialValues); + }, [users]); const form = useForm>({ resolver: zodResolver(passwordSet), @@ -87,6 +118,52 @@ export function UserCard({ users }: UserListProps) { }, }); + const { mutate: price_type_set } = useMutation({ + mutationFn: ({ + id, + body, + }: { + id: number | string; + body: { ids: number[] }; + }) => user_api.price_type_set({ body, id }), + onSuccess: () => { + setOpenPriceId(null); + queryClient.refetchQueries({ queryKey: ["user_list"] }); + toast.success("Narx qo'yildi", { + richColors: true, + position: "top-center", + }); + }, + onError: (err: AxiosError) => { + const errData = (err.response?.data as { data: string }).data; + const errMessage = (err.response?.data as { message: string }).message; + + toast.error(errData || errMessage || "Xatolik yuz berdi", { + richColors: true, + position: "top-center", + }); + }, + }); + + const toggleValue = (userId: string | number, value: string) => { + let newUserValues: string[] = []; + + setValues((prev) => { + const userValues = prev[userId] || []; + newUserValues = userValues.includes(value) + ? userValues.filter((v) => v !== value) + : [...userValues, value]; + return { ...prev, [userId]: newUserValues }; + }); + const currentUserValues = values[userId] || []; + const nextUserValues = currentUserValues.includes(value) + ? currentUserValues.filter((v) => v !== value) + : [...currentUserValues, value]; + + setValues((prev) => ({ ...prev, [userId]: nextUserValues })); + price_type_set({ body: { ids: nextUserValues.map(Number) }, id: userId }); + }; + function onSubmit(value: z.infer) { if (edit) { mutate({ body: { password: value.password }, id: edit }); @@ -102,107 +179,178 @@ export function UserCard({ users }: UserListProps) { To'liq ism Username Ro'yxatdan o'tgan + Biriktirilgan narx Amallar - {users.map((user) => ( - - {user.id} - -
- {user.name} -
-
- - @{user.username} - + {users.map((user) => { + const userValues = values[user.id] || []; + return ( + + {user.id} + +
+ {user.name} +
+
+ + + @{user.username} + + - - - {formatDate.format(user.created_at, "DD-MM-YYYY")} - - - - { - setOpen(isOpen); - if (!isOpen) { - setEdit(null); - form.reset(); + + + {formatDate.format(user.created_at, "DD-MM-YYYY")} + + + + + setOpenPriceId(isOpen ? user.id : null) } - }} - > - - - - - - Parolni {user.password_set ? "o'zgartirish" : "qo'yish"} - -
-
- - ( - - - - + + + + + + + + Topilmadi. + + {data?.map((option) => { + const isSelected = userValues.includes( + option.id.toString(), + ); + + return ( + + toggleValue(user.id, option.id.toString()) + } + className="cursor-pointer" + > + - - - - )} - /> -
- - -
- - -
-
-
-
-
- ))} + {option.name} + + ); + })} + + + + + + + + { + setOpen(isOpen); + if (!isOpen) { + setEdit(null); + form.reset(); + } + }} + > + + + + + + Parolni {user.password_set ? "o'zgartirish" : "qo'yish"} + +
+
+ + ( + + + + + + + + )} + /> +
+ + +
+ + +
+
+
+
+
+ ); + })}
diff --git a/src/shared/config/api/URLs.ts b/src/shared/config/api/URLs.ts index 2137ce4..5a7e6e0 100644 --- a/src/shared/config/api/URLs.ts +++ b/src/shared/config/api/URLs.ts @@ -47,4 +47,6 @@ export const API_URLS = { Update_Pyment_Type: (id: number) => `${API_V}admin/product/${id}/update_payment_type/`, Import_Balance: `${API_V}admin/product/import/balance/`, + PriceTypeSet: (id: number | string) => + `${API_V}admin/user/${id}/set_price_type/`, };