diff --git a/src/app/(admin)/(masters)/client-apps/confirm-delete.tsx b/src/app/(admin)/(masters)/client-apps/confirm-delete.tsx new file mode 100644 index 0000000..3870737 --- /dev/null +++ b/src/app/(admin)/(masters)/client-apps/confirm-delete.tsx @@ -0,0 +1,15 @@ +'use client' +import { FormDelete } from "@/components/forms/form-delete" +import { useDeleteClientApps } from "@/modules/client-apps/hooks/useClientApps" + +export function ConfirmDelete({ id }: { id: string }) { + const { mutate, isPending } = useDeleteClientApps() + return ( + mutate(id)} + isLoading={isPending} + title="Delete Data?" + description="This will permanently delete this data from the system." + /> + ) +} \ No newline at end of file diff --git a/src/app/(admin)/(masters)/client-apps/form-submit.tsx b/src/app/(admin)/(masters)/client-apps/form-submit.tsx new file mode 100644 index 0000000..34187f4 --- /dev/null +++ b/src/app/(admin)/(masters)/client-apps/form-submit.tsx @@ -0,0 +1,126 @@ +"use client" +import { FormInput } from "@/components/forms/form-input" +import { Icon } from "@/components/icon" +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" +import { Form } from "@/components/ui/form" +import { ScrollArea } from "@/components/ui/scroll-area" +import { useCreateClientApps, useUpdateClientApps } from "@/modules/client-apps/hooks/useClientApps" +import { formClientAppSchema } from "@/modules/client-apps/schema" +import { TClientApps, TFormClientApps } from "@/types/client-apps" +import { zodResolver } from "@hookform/resolvers/zod" +import { useState } from "react" +import { useForm } from "react-hook-form" + +export function FormSubmit({ data }: { data?: TClientApps }) { + const [dialog, setDialog] = useState(false) + const { mutate: createClientApps, isPending: updating } = useCreateClientApps() + const { mutate: updateClientApps, isPending: creating } = useUpdateClientApps() + const form = useForm({ + resolver: zodResolver(formClientAppSchema), + defaultValues: { + name: "", + code: "", + url: "", + description: "" + }, + }) + + function onSubmit(values: TFormClientApps) { + if (data?.id) { + updateClientApps({ id: data.id, data: values }, { + onSuccess: () => { + setDialog(false) + } + }) + } else { + createClientApps(values, { + onSuccess: () => { + setDialog(false) + } + }) + + } + } + function handleOpen() { + setDialog(!dialog) + form.reset({ + name: data?.name, + code: data?.code, + url: data?.url || '-', + description: data?.description || '-', + }) + } + return ( + +
+ + { + data?.id ? ( + + ) : ( + + ) + } + + + + Form Apps + + Make changes to your chain here. Click save when you're + done. + + +
+ + + +
+ + + + +
+
+
+ + + + + + +
+ + +
+
+ +
+ ) +} diff --git a/src/app/(admin)/(masters)/client-apps/page.tsx b/src/app/(admin)/(masters)/client-apps/page.tsx new file mode 100644 index 0000000..8a802fa --- /dev/null +++ b/src/app/(admin)/(masters)/client-apps/page.tsx @@ -0,0 +1,10 @@ +import PageContainer from '@/components/page-container' +import Table from './table' + +export default function ClientAppPage() { + return ( + + + + ) +} diff --git a/src/app/(admin)/(masters)/client-apps/table/columns.tsx b/src/app/(admin)/(masters)/client-apps/table/columns.tsx new file mode 100644 index 0000000..b9483de --- /dev/null +++ b/src/app/(admin)/(masters)/client-apps/table/columns.tsx @@ -0,0 +1,44 @@ +import PermissionContainer from "@/components/permission-container"; +import { TClientApps } from "@/types/client-apps"; +import { ColumnDef } from "@tanstack/react-table"; +import { ConfirmDelete } from "../confirm-delete"; +import { FormSubmit } from "../form-submit"; +import Link from "next/link"; +export const columns: ColumnDef[] = [ + { + accessorKey: 'name', + header: 'Name', + }, + { + accessorKey: 'code', + header: 'Code', + }, + { + accessorKey: 'url', + header: 'Urls', + cell: ({ row }) => { + return ( + + {row.original.url ?? "-"} + + ) + } + }, + { + id: "actions", + enableHiding: false, + cell: ({ row }) => { + return ( +
+ + + + + + +
+ ) + } + } +] + diff --git a/src/app/(admin)/(masters)/client-apps/table/index.tsx b/src/app/(admin)/(masters)/client-apps/table/index.tsx new file mode 100644 index 0000000..313602c --- /dev/null +++ b/src/app/(admin)/(masters)/client-apps/table/index.tsx @@ -0,0 +1,36 @@ +'use client' +import DataTable from '@/components/datatable' +import PermissionContainer from '@/components/permission-container' +import { useClientApps } from '@/modules/client-apps/hooks/useClientApps' +import { TClientApps } from '@/types/client-apps' +import { useRouter, useSearchParams } from 'next/navigation' +import { FormSubmit } from '../form-submit' +import { columns } from './columns' + +export default function Table() { + const { data, isLoading } = useClientApps() + + const router = useRouter() + const searchParams = useSearchParams() + async function onPageChange(e: number) { + const params = new URLSearchParams(searchParams.toString()) + params.set('page', String(e + 1)) + router.push(`?${params.toString()}`) + } + return ( + + actions={ + + + + } + data={data?.data || []} + columns={columns} + pageCount={data?.meta?.lastPage} + pageIndex={data?.meta.currentPage ? data?.meta.currentPage - 1 : 0} + pageSize={data?.meta.lastPage} + onPageChange={onPageChange} + isLoading={isLoading} + /> + ) +} diff --git a/src/modules/client-apps/client-apps.service.ts b/src/modules/client-apps/client-apps.service.ts new file mode 100644 index 0000000..15e6257 --- /dev/null +++ b/src/modules/client-apps/client-apps.service.ts @@ -0,0 +1,9 @@ +import { BaseService } from "@/services/base.service" +import { TClientApps, TFormClientApps } from "@/types/client-apps" + +class ClientApp extends BaseService { + protected endpoint = 'client-apps' +} + +const clientApp = new ClientApp() +export default clientApp diff --git a/src/modules/client-apps/hooks/useClientApps.ts b/src/modules/client-apps/hooks/useClientApps.ts new file mode 100644 index 0000000..11cc241 --- /dev/null +++ b/src/modules/client-apps/hooks/useClientApps.ts @@ -0,0 +1,90 @@ +"use client" +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { useSearchParams } from "next/navigation"; +import service from "../client-apps.service"; +import { toast } from "sonner"; +import { toObjectQuery } from "@/lib/param"; +import { TFormClientApps } from "@/types/client-apps"; + + +export const useClientApps = () => { + const searchString = useSearchParams(); + const query = toObjectQuery(searchString) + const queryChain = useQuery({ + queryKey: ["get_client_app", query], + queryFn: () => service.GET(query), + enabled: true + }); + return queryChain +} + +export const useCreateClientApps = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: (data: TFormClientApps) => service.CREATE(data), + onSuccess: () => { + toast.success('Success', { + description: "Success submit data" + }) + queryClient.invalidateQueries({ + queryKey: ["get_client_app"] + }); + }, + onError: () => { + toast.error('Error', { + description: "Fail to submit data!" + }) + } + }); +}; +export const useDeleteClientApps = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: (id: string) => service.DELETE(id), + onSuccess: () => { + toast.success('Success', { + description: "Success delete data" + }) + queryClient.invalidateQueries({ + queryKey: ["get_client_app"] + }); + }, + onError: () => { + toast.error('Error', { + description: "Fail to delete data!" + }) + } + }); +}; + +export const useUpdateClientApps = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: ( + { id, data }: { id: string; data: TFormClientApps } + ) => service.UPDATE(id, data), + onSuccess: () => { + toast.success('Success', { + description: "Success submit data" + }) + queryClient.invalidateQueries({ + queryKey: ["get_client_app"] + }); + }, + onError: () => { + toast.error('Error', { + description: "Fail to submit data!" + }) + } + }); +}; + +// extra +export const useClientAppsList = () => { + const query = useQuery({ + queryKey: ["get_client_app_list"], + queryFn: () => service.LISTS(), + enabled: true + }); + return query +} \ No newline at end of file diff --git a/src/modules/client-apps/schema.ts b/src/modules/client-apps/schema.ts new file mode 100644 index 0000000..b2f74e7 --- /dev/null +++ b/src/modules/client-apps/schema.ts @@ -0,0 +1,15 @@ +"use client" + +import { z } from "zod" +export const formClientAppSchema = z.object({ + name: z.string().min(1, { + message: 'required' + }), + code: z.string().min(1, { + message: 'required' + }), + url: z.string().min(1, { + message: 'required' + }), + description: z.string().optional().nullable() +}) \ No newline at end of file diff --git a/src/types/client-apps.d.ts b/src/types/client-apps.d.ts new file mode 100644 index 0000000..e1b4528 --- /dev/null +++ b/src/types/client-apps.d.ts @@ -0,0 +1,13 @@ +import { formClientAppSchema } from "@/modules/client-apps/schema" +import { z } from "zod" + + +export type TFormClientApps = z.infer + +export type TClientApps = { + id: string + name: string + code: string + url: string + description?: string | null +}