Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/app/(admin)/(masters)/client-apps/confirm-delete.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<FormDelete
onConfirm={() => mutate(id)}
isLoading={isPending}
title="Delete Data?"
description="This will permanently delete this data from the system."
/>
)
}
126 changes: 126 additions & 0 deletions src/app/(admin)/(masters)/client-apps/form-submit.tsx
Original file line number Diff line number Diff line change
@@ -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<TFormClientApps>({
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 (
<Dialog open={dialog} onOpenChange={handleOpen}>
<form>
<DialogTrigger asChild>
{
data?.id ? (
<Button size={"icon-sm"}><Icon name="mdi:pencil" /></Button>
) : (
<Button>Add New</Button>
)
}
</DialogTrigger>
<DialogContent className="sm:max-w-2xl">
<DialogHeader>
<DialogTitle>Form Apps</DialogTitle>
<DialogDescription>
Make changes to your chain here. Click save when you&apos;re
done.
</DialogDescription>
</DialogHeader>
<div>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-3">
<ScrollArea className="h-[60vh] md:h-auto">
<div className="space-y-4 p-2">
<FormInput
placeholder="name"
label="Name" name={"name"}
control={form.control}
/>
<FormInput
placeholder="code"
label="Code" name={"code"}
control={form.control}
/>
<FormInput
placeholder="url"
label="Url" name={"url"}
control={form.control}
/>
<FormInput
isLongText
placeholder="description"
label="Description" name={"description"}
control={form.control}
/>
</div>
</ScrollArea>
<div className="mt-4">
<DialogFooter>
<DialogClose asChild>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button disabled={updating || creating} type="submit">Save</Button>
</DialogFooter>
</div>
</form>
</Form>
</div>
</DialogContent>
</form>
</Dialog>
)
}
10 changes: 10 additions & 0 deletions src/app/(admin)/(masters)/client-apps/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import PageContainer from '@/components/page-container'
import Table from './table'

export default function ClientAppPage() {
return (
<PageContainer title='Client App' subtitle='List Of Clien App'>
<Table />
</PageContainer>
)
}
44 changes: 44 additions & 0 deletions src/app/(admin)/(masters)/client-apps/table/columns.tsx
Original file line number Diff line number Diff line change
@@ -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<TClientApps>[] = [
{
accessorKey: 'name',
header: 'Name',
},
{
accessorKey: 'code',
header: 'Code',
},
{
accessorKey: 'url',
header: 'Urls',
cell: ({ row }) => {
return (
<Link className="line-clamp-1" href={'/'} target="_blank" rel="noopener noreferrer">
{row.original.url ?? "-"}
</Link>
)
}
},
{
id: "actions",
enableHiding: false,
cell: ({ row }) => {
return (
<div className="flex items-center justify-end gap-1">
<PermissionContainer permission='PATCH_chains/:id'>
<FormSubmit data={{ ...row.original }} />
</PermissionContainer>
<PermissionContainer permission='DELETE_chains/:id'>
<ConfirmDelete id={row.original.id} />
</PermissionContainer>
</div>
)
}
}
]

36 changes: 36 additions & 0 deletions src/app/(admin)/(masters)/client-apps/table/index.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<DataTable<TClientApps>
actions={
<PermissionContainer permission='POST_chains'>
<FormSubmit />
</PermissionContainer>
}
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}
/>
)
}
9 changes: 9 additions & 0 deletions src/modules/client-apps/client-apps.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { BaseService } from "@/services/base.service"
import { TClientApps, TFormClientApps } from "@/types/client-apps"

class ClientApp extends BaseService<TClientApps, TFormClientApps> {
protected endpoint = 'client-apps'
}

const clientApp = new ClientApp()
export default clientApp
90 changes: 90 additions & 0 deletions src/modules/client-apps/hooks/useClientApps.ts
Original file line number Diff line number Diff line change
@@ -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
}
15 changes: 15 additions & 0 deletions src/modules/client-apps/schema.ts
Original file line number Diff line number Diff line change
@@ -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()
})
13 changes: 13 additions & 0 deletions src/types/client-apps.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { formClientAppSchema } from "@/modules/client-apps/schema"
import { z } from "zod"


export type TFormClientApps = z.infer<typeof formClientAppSchema>

export type TClientApps = {
id: string
name: string
code: string
url: string
description?: string | null
}
Loading