From 525333ac71e918f923e8dc626dbd1e840fcf5f91 Mon Sep 17 00:00:00 2001 From: Khoironi Kurnia Syah Date: Mon, 26 Aug 2024 22:41:54 +0800 Subject: [PATCH] feat: adjustment role form --- .../dashboard/(admin)/users/page.tsx | 21 +- .../dashboard/(admin)/users/role-form.tsx | 15 +- src/components/private/header.tsx | 2 +- src/components/ui/alert.tsx | 93 ++++--- src/components/ui/scroll-area.tsx | 82 +++--- src/components/ui/select.tsx | 262 +++++++++--------- src/lib/actions/{auth.ts => auth.action.ts} | 0 src/lib/actions/index.ts | 6 +- src/lib/actions/roles.action.ts | 37 +++ src/lib/actions/roles.ts | 15 - src/lib/actions/{users.ts => users.action.ts} | 0 src/lib/mutations/index.ts | 1 + src/lib/mutations/roles.mutation.ts | 23 ++ src/lib/queries/index.ts | 2 + src/lib/queries/roles.query.ts | 4 +- src/lib/schema/roles.schema.ts | 10 +- 16 files changed, 308 insertions(+), 265 deletions(-) rename src/lib/actions/{auth.ts => auth.action.ts} (100%) create mode 100644 src/lib/actions/roles.action.ts delete mode 100644 src/lib/actions/roles.ts rename src/lib/actions/{users.ts => users.action.ts} (100%) create mode 100644 src/lib/mutations/index.ts create mode 100644 src/lib/mutations/roles.mutation.ts create mode 100644 src/lib/queries/index.ts diff --git a/src/app/(private)/dashboard/(admin)/users/page.tsx b/src/app/(private)/dashboard/(admin)/users/page.tsx index 278d927..08e5a5f 100644 --- a/src/app/(private)/dashboard/(admin)/users/page.tsx +++ b/src/app/(private)/dashboard/(admin)/users/page.tsx @@ -1,9 +1,7 @@ 'use client'; import { Menu, Users } from 'lucide-react'; -import { useState } from 'react'; -import { useGetRoles } from '@/lib/queries/roles.query'; import { useGetUsers } from '@/lib/queries/users.query'; import { Button } from '@/components/ui/button'; @@ -28,26 +26,11 @@ import { import RoleFormDialog from './role-form'; export default function Component() { - const { - data: roleData, - isLoading: isRoleLoading, - error: roleError, - } = useGetRoles({}); - const { data: userData, - isLoading: isuserLoading, - error: userError, + // isLoading: isuserLoading, + // error: userError, } = useGetUsers({}); - const [newMember, setNewMember] = useState({ - name: '', - email: '', - role: '', - }); - const [newRole, setNewRole] = useState(''); - const [editingRole, setEditingRole] = useState(''); - console.error(userData, 'userData'); - return (
diff --git a/src/app/(private)/dashboard/(admin)/users/role-form.tsx b/src/app/(private)/dashboard/(admin)/users/role-form.tsx index e7b4282..0d29e46 100644 --- a/src/app/(private)/dashboard/(admin)/users/role-form.tsx +++ b/src/app/(private)/dashboard/(admin)/users/role-form.tsx @@ -10,7 +10,8 @@ import { } from 'lucide-react'; import { useState } from 'react'; -import { useGetRoles } from '@/lib/queries/roles.query'; +import { useCreateRole, useDeleteRole, useEditRoleName } from '@/lib/mutations'; +import { useGetRoles } from '@/lib/queries'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Button } from '@/components/ui/button'; @@ -26,6 +27,9 @@ import { Input } from '@/components/ui/input'; import { ScrollArea } from '@/components/ui/scroll-area'; export default function RoleFormDialog() { + const editMutation = useEditRoleName(); + const createMutation = useCreateRole(); + const deleteMutation = useDeleteRole(); const [newRoleName, setNewRoleName] = useState(''); const { data: roleData, @@ -35,20 +39,17 @@ export default function RoleFormDialog() { } = useGetRoles({}); const handleAddRole = () => { - // Implement add role logic here - console.log('Adding new role:', newRoleName); + createMutation.mutate(newRoleName); setNewRoleName(''); refetchRoles(); }; const handleEditRole = (roleId: string) => { - // Implement edit role logic here - console.log('Editing role:', roleId); + editMutation.mutate({ roleId, name: 'new name' }); }; const handleDeleteRole = (roleId: string) => { - // Implement delete role logic here - console.log('Deleting role:', roleId); + deleteMutation.mutate(roleId); refetchRoles(); }; diff --git a/src/components/private/header.tsx b/src/components/private/header.tsx index 7f6c524..78d60cc 100644 --- a/src/components/private/header.tsx +++ b/src/components/private/header.tsx @@ -4,7 +4,7 @@ import { CircleUser, Menu, Sparkles } from 'lucide-react'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; -import { signOut } from '@/lib/actions/auth'; +import { signOut } from '@/lib/actions/auth.action'; import { DatabaseUserAttributes } from '@/lib/auth'; import { Button } from '@/components/ui/button'; diff --git a/src/components/ui/alert.tsx b/src/components/ui/alert.tsx index 41fa7e0..cda6a59 100644 --- a/src/components/ui/alert.tsx +++ b/src/components/ui/alert.tsx @@ -1,59 +1,62 @@ -import * as React from "react" -import { cva, type VariantProps } from "class-variance-authority" +import { cva, type VariantProps } from 'class-variance-authority'; +import * as React from 'react'; -import { cn } from "@/lib/utils" +import { cn } from '@/lib/utils'; const alertVariants = cva( - "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", - { - variants: { - variant: { - default: "bg-background text-foreground", - destructive: - "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", - }, + 'relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground', + { + variants: { + variant: { + default: 'bg-background text-foreground', + destructive: + 'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive', + }, + }, + defaultVariants: { + variant: 'default', + }, }, - defaultVariants: { - variant: "default", - }, - } -) +); const Alert = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes & VariantProps + HTMLDivElement, + React.HTMLAttributes & VariantProps >(({ className, variant, ...props }, ref) => ( -
-)) -Alert.displayName = "Alert" +
+)); +Alert.displayName = 'Alert'; const AlertTitle = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes + HTMLParagraphElement, + React.HTMLAttributes >(({ className, ...props }, ref) => ( -
-)) -AlertTitle.displayName = "AlertTitle" +
+)); +AlertTitle.displayName = 'AlertTitle'; const AlertDescription = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes + HTMLParagraphElement, + React.HTMLAttributes >(({ className, ...props }, ref) => ( -
-)) -AlertDescription.displayName = "AlertDescription" +
+)); +AlertDescription.displayName = 'AlertDescription'; -export { Alert, AlertTitle, AlertDescription } +export { Alert, AlertDescription, AlertTitle }; diff --git a/src/components/ui/scroll-area.tsx b/src/components/ui/scroll-area.tsx index 0b4a48d..2402f47 100644 --- a/src/components/ui/scroll-area.tsx +++ b/src/components/ui/scroll-area.tsx @@ -1,48 +1,50 @@ -"use client" +'use client'; -import * as React from "react" -import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area" +import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'; +import * as React from 'react'; -import { cn } from "@/lib/utils" +import { cn } from '@/lib/utils'; const ScrollArea = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - - - {children} - - - - -)) -ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName + + + {children} + + + + +)); +ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName; const ScrollBar = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, orientation = "vertical", ...props }, ref) => ( - - - -)) -ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName + React.ElementRef, + React.ComponentPropsWithoutRef< + typeof ScrollAreaPrimitive.ScrollAreaScrollbar + > +>(({ className, orientation = 'vertical', ...props }, ref) => ( + + + +)); +ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName; -export { ScrollArea, ScrollBar } +export { ScrollArea, ScrollBar }; diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx index cbe5a36..e7e03ed 100644 --- a/src/components/ui/select.tsx +++ b/src/components/ui/select.tsx @@ -1,160 +1,160 @@ -"use client" +'use client'; -import * as React from "react" -import * as SelectPrimitive from "@radix-ui/react-select" -import { Check, ChevronDown, ChevronUp } from "lucide-react" +import * as SelectPrimitive from '@radix-ui/react-select'; +import { Check, ChevronDown, ChevronUp } from 'lucide-react'; +import * as React from 'react'; -import { cn } from "@/lib/utils" +import { cn } from '@/lib/utils'; -const Select = SelectPrimitive.Root +const Select = SelectPrimitive.Root; -const SelectGroup = SelectPrimitive.Group +const SelectGroup = SelectPrimitive.Group; -const SelectValue = SelectPrimitive.Value +const SelectValue = SelectPrimitive.Value; const SelectTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - span]:line-clamp-1", - className - )} - {...props} - > - {children} - - - - -)) -SelectTrigger.displayName = SelectPrimitive.Trigger.displayName + span]:line-clamp-1', + className, + )} + {...props} + > + {children} + + + + +)); +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName; const SelectScrollUpButton = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - - - -)) -SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName + + + +)); +SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName; const SelectScrollDownButton = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - - - -)) + + + +)); SelectScrollDownButton.displayName = - SelectPrimitive.ScrollDownButton.displayName + SelectPrimitive.ScrollDownButton.displayName; const SelectContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, position = "popper", ...props }, ref) => ( - - - - - {children} - - - - -)) -SelectContent.displayName = SelectPrimitive.Content.displayName + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, position = 'popper', ...props }, ref) => ( + + + + + {children} + + + + +)); +SelectContent.displayName = SelectPrimitive.Content.displayName; const SelectLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -SelectLabel.displayName = SelectPrimitive.Label.displayName + +)); +SelectLabel.displayName = SelectPrimitive.Label.displayName; const SelectItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - - - - - - + + + + + + - {children} - -)) -SelectItem.displayName = SelectPrimitive.Item.displayName + {children} + +)); +SelectItem.displayName = SelectPrimitive.Item.displayName; const SelectSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -SelectSeparator.displayName = SelectPrimitive.Separator.displayName + +)); +SelectSeparator.displayName = SelectPrimitive.Separator.displayName; export { - Select, - SelectGroup, - SelectValue, - SelectTrigger, - SelectContent, - SelectLabel, - SelectItem, - SelectSeparator, - SelectScrollUpButton, - SelectScrollDownButton, -} + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectScrollDownButton, + SelectScrollUpButton, + SelectSeparator, + SelectTrigger, + SelectValue, +}; diff --git a/src/lib/actions/auth.ts b/src/lib/actions/auth.action.ts similarity index 100% rename from src/lib/actions/auth.ts rename to src/lib/actions/auth.action.ts diff --git a/src/lib/actions/index.ts b/src/lib/actions/index.ts index aadee9f..3f4019d 100644 --- a/src/lib/actions/index.ts +++ b/src/lib/actions/index.ts @@ -1,3 +1,3 @@ -export * from './auth'; -export * from './roles'; -export * from './users'; +export * from './auth.action'; +export * from './roles.action'; +export * from './users.action'; diff --git a/src/lib/actions/roles.action.ts b/src/lib/actions/roles.action.ts new file mode 100644 index 0000000..32595e8 --- /dev/null +++ b/src/lib/actions/roles.action.ts @@ -0,0 +1,37 @@ +'use server'; + +import { and, desc, eq, ilike } from 'drizzle-orm'; + +import { SearchRole } from '@/lib/schema'; + +import { database, role } from '@/database'; + +export async function getRoles(search: SearchRole) { + return await database + .select() + .from(role) + .where(and(search.name ? ilike(role.name, search.name) : undefined)) + .orderBy(desc(role.createdAt)); +} + +export async function editRoleName(roleId: string, name: string) { + return await database + .update(role) + .set({ + name, + }) + .where(eq(role.id, roleId)); +} + +export async function deleteRole(roleId: string) { + return await database.delete(role).where(eq(role.id, roleId)); +} + +export async function createRole(name: string) { + return await database + .insert(role) + .values({ + name, + }) + .returning(); +} diff --git a/src/lib/actions/roles.ts b/src/lib/actions/roles.ts deleted file mode 100644 index 201fa0d..0000000 --- a/src/lib/actions/roles.ts +++ /dev/null @@ -1,15 +0,0 @@ -'use server'; - -import { and, desc, ilike } from 'drizzle-orm'; - -import { RoleSearch } from '@/lib/schema'; - -import { database, role } from '@/database'; - -export async function getRoles(search: RoleSearch) { - return await database - .select() - .from(role) - .where(and(search.name ? ilike(role.name, search.name) : undefined)) - .orderBy(desc(role.createdAt)); -} diff --git a/src/lib/actions/users.ts b/src/lib/actions/users.action.ts similarity index 100% rename from src/lib/actions/users.ts rename to src/lib/actions/users.action.ts diff --git a/src/lib/mutations/index.ts b/src/lib/mutations/index.ts new file mode 100644 index 0000000..79a0f21 --- /dev/null +++ b/src/lib/mutations/index.ts @@ -0,0 +1 @@ +export * from './roles.mutation'; diff --git a/src/lib/mutations/roles.mutation.ts b/src/lib/mutations/roles.mutation.ts new file mode 100644 index 0000000..52eb5ee --- /dev/null +++ b/src/lib/mutations/roles.mutation.ts @@ -0,0 +1,23 @@ +import { useMutation } from '@tanstack/react-query'; + +import { createRole, deleteRole, editRoleName } from '@/lib/actions'; +import { EditRoleName } from '@/lib/schema'; + +export function useEditRoleName() { + return useMutation({ + mutationFn: (payload: EditRoleName) => + editRoleName(payload.roleId, payload.name), + }); +} + +export function useDeleteRole() { + return useMutation({ + mutationFn: (roleId: string) => deleteRole(roleId), + }); +} + +export function useCreateRole() { + return useMutation({ + mutationFn: (name: string) => createRole(name), + }); +} diff --git a/src/lib/queries/index.ts b/src/lib/queries/index.ts new file mode 100644 index 0000000..6c5201c --- /dev/null +++ b/src/lib/queries/index.ts @@ -0,0 +1,2 @@ +export * from './roles.query'; +export * from './users.query'; diff --git a/src/lib/queries/roles.query.ts b/src/lib/queries/roles.query.ts index c803e46..7f82bde 100644 --- a/src/lib/queries/roles.query.ts +++ b/src/lib/queries/roles.query.ts @@ -1,9 +1,9 @@ import { useQuery } from '@tanstack/react-query'; import { getRoles } from '@/lib/actions'; -import { RoleSearch } from '@/lib/schema'; +import { SearchRole } from '@/lib/schema'; -export function useGetRoles(search: RoleSearch) { +export function useGetRoles(search: SearchRole) { return useQuery({ queryKey: ['roles', search], queryFn: () => getRoles(search), diff --git a/src/lib/schema/roles.schema.ts b/src/lib/schema/roles.schema.ts index ef3cbbf..e6e147a 100644 --- a/src/lib/schema/roles.schema.ts +++ b/src/lib/schema/roles.schema.ts @@ -1,7 +1,13 @@ import { z } from 'zod'; -export const RoleSearchSchema = z.object({ +export const SearchRoleSchema = z.object({ name: z.string().optional(), }); -export type RoleSearch = z.infer; +export const EditRoleNameSchema = z.object({ + roleId: z.string(), + name: z.string(), +}); + +export type EditRoleName = z.infer; +export type SearchRole = z.infer;