summaryrefslogtreecommitdiff
path: root/lib/roles/table/assign-roles-sheet.tsx
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-07-15 10:07:09 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-07-15 10:07:09 +0000
commit4eb7532f822c821fb6b69bf103bd075fefba769b (patch)
treeb4bcf6c0bf791d71569f3f35498ed256bf7cfaf3 /lib/roles/table/assign-roles-sheet.tsx
parent660c7888d885badab7af3e96f9c16bd0172ad0f1 (diff)
(대표님) 20250715 협력사 정기평가, spreadJS, roles 서비스에 함수 추가
Diffstat (limited to 'lib/roles/table/assign-roles-sheet.tsx')
-rw-r--r--lib/roles/table/assign-roles-sheet.tsx168
1 files changed, 136 insertions, 32 deletions
diff --git a/lib/roles/table/assign-roles-sheet.tsx b/lib/roles/table/assign-roles-sheet.tsx
index 11c6a1ff..d750081c 100644
--- a/lib/roles/table/assign-roles-sheet.tsx
+++ b/lib/roles/table/assign-roles-sheet.tsx
@@ -1,10 +1,7 @@
"use client"
import * as React from "react"
-import { zodResolver } from "@hookform/resolvers/zod"
-import { useForm } from "react-hook-form"
import { toast } from "sonner"
-
import {
Sheet,
SheetClose,
@@ -15,71 +12,178 @@ import {
SheetTitle,
} from "@/components/ui/sheet"
import { Button } from "@/components/ui/button"
-import { Loader } from "lucide-react"
+import { Loader, Plus, Minus, Users } from "lucide-react"
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+import { Badge } from "@/components/ui/badge"
import { AssginedUserTable } from "../userTable/assignedUsers-table"
-import { assignUsersToRole } from "@/lib/users/service"
+import { assignUsersToRole, removeUsersFromRole } from "@/lib/users/service"
import { RoleView } from "@/db/schema/users"
-export interface UpdateRoleSheetProps
+export interface ManageRoleSheetProps
extends React.ComponentPropsWithRef<typeof Sheet> {
role: RoleView | null
-
- // ★ 새로 추가: 테이블에 필요한 데이터 로딩 promise
- assignedTablePromises: Promise<[
- { data: any[]; pageCount: number }
-
- ]>
+ // 현재 구조에 맞춰 allUsersPromises 사용
+ allUsersPromises: Promise<[{ data: any[]; pageCount: number }]>
}
-export function AssignRolesSheet({ role, assignedTablePromises, ...props }: UpdateRoleSheetProps) {
-
+export function ManageRoleSheet({
+ role,
+ allUsersPromises,
+ ...props
+}: ManageRoleSheetProps) {
const [isUpdatePending, startUpdateTransition] = React.useTransition()
const [selectedUserIds, setSelectedUserIds] = React.useState<number[]>([])
+ const [activeTab, setActiveTab] = React.useState("assign")
- // 2) 자식에서 호출될 콜백
function handleSelectedChange(ids: number[]) {
setSelectedUserIds(ids)
}
async function handleAssign() {
+ if (!role || selectedUserIds.length === 0) {
+ toast.error("선택된 사용자가 없습니다.")
+ return
+ }
+
+ startUpdateTransition(async () => {
+ const { data, error } = await assignUsersToRole(role.id, selectedUserIds)
+ if (error) {
+ toast.error(error)
+ return
+ }
+
+ setSelectedUserIds([]) // 선택 초기화
+ toast.success(data?.message || `${selectedUserIds.length}명의 사용자가 "${role.name}" 롤에 할당되었습니다.`)
+
+ // 작업 완료 후 시트를 닫지 않고 유지 (계속 작업할 수 있도록)
+ })
+ }
+
+ async function handleRemove() {
+ if (!role || selectedUserIds.length === 0) {
+ toast.error("선택된 사용자가 없습니다.")
+ return
+ }
+
startUpdateTransition(async () => {
- if (!role) return
- const { error } = await assignUsersToRole(role.id, selectedUserIds)
+ const { data, error } = await removeUsersFromRole(role.id, selectedUserIds)
if (error) {
toast.error(error)
return
}
- props.onOpenChange?.(false)
- toast.success(`Assigned ${selectedUserIds.length} users!`)
+
+ setSelectedUserIds([]) // 선택 초기화
+ toast.success(data?.message || `${selectedUserIds.length}명의 사용자가 "${role.name}" 롤에서 제거되었습니다.`)
})
}
+ // 탭 변경시 선택 초기화
+ React.useEffect(() => {
+ setSelectedUserIds([])
+ }, [activeTab])
+
+ // 롤 변경시 선택 초기화
+ React.useEffect(() => {
+ setSelectedUserIds([])
+ setActiveTab("assign") // 기본적으로 assign 탭으로 리셋
+ }, [role?.id])
+
+ // 시트가 닫힐 때 상태 초기화
+ React.useEffect(() => {
+ if (!props.open) {
+ setSelectedUserIds([])
+ setActiveTab("assign")
+ }
+ }, [props.open])
+
return (
<Sheet {...props}>
- <SheetContent className="flex flex-col gap-6 sm:max-w-md">
+ <SheetContent className="flex flex-col gap-6 sm:max-w-md" style={{width: 1000, maxWidth: 1000}}>
<SheetHeader className="text-left">
- <SheetTitle>"{role?.name}"에 유저를 할당하세요</SheetTitle>
- <SheetDescription>
- 현재 {role?.name}에는 {role?.user_count}명이 할당되어있습니다. 이 롤은 다음과 같습니다.<br/> {role?.description}
+ <SheetTitle className="flex items-center gap-2">
+ <Users className="h-5 w-5" />
+ Manage "{role?.name}" Role
+ </SheetTitle>
+ <SheetDescription className="space-y-2">
+ <div className="flex items-center gap-2">
+ <span>Currently assigned:</span>
+ <Badge variant="secondary">{role?.user_count || 0} users</Badge>
+ </div>
+ <div className="text-sm">
+ {role?.description}
+ </div>
</SheetDescription>
</SheetHeader>
- <AssginedUserTable promises={assignedTablePromises} onSelectedChange={handleSelectedChange} />
+ <Tabs value={activeTab} onValueChange={setActiveTab} className="flex-1">
+ <TabsList className="grid w-full grid-cols-2">
+ <TabsTrigger value="assign" className="flex items-center gap-2">
+ <Plus className="h-4 w-4" />
+ Assign Users
+ </TabsTrigger>
+ <TabsTrigger value="remove" className="flex items-center gap-2">
+ <Minus className="h-4 w-4" />
+ Remove Users
+ </TabsTrigger>
+ </TabsList>
+
+ <TabsContent value="assign" className="flex-1 mt-4">
+ <div className="mb-3 text-sm text-muted-foreground">
+ Select users to assign to this role:
+
+ </div>
+ <AssginedUserTable
+ promises={allUsersPromises}
+ onSelectedChange={handleSelectedChange}
+ mode="assign"
+ currentRoleName={role?.name}
+ />
+ </TabsContent>
+
+ <TabsContent value="remove" className="flex-1 mt-4">
+ <div className="mb-3 text-sm text-muted-foreground">
+ Select users to remove from this role:
+ </div>
+ <AssginedUserTable
+ promises={allUsersPromises}
+ onSelectedChange={handleSelectedChange}
+ mode="remove"
+ currentRoleName={role?.name}
+ />
+ </TabsContent>
+ </Tabs>
<SheetFooter className="gap-2 pt-2 sm:space-x-0">
- <SheetClose asChild>
+ <SheetClose asChild>
<Button type="button" variant="outline">
Cancel
</Button>
</SheetClose>
- {/* <Button disabled={isUpdatePending} onClick={onSubmitAssignUsers}> */}
- <Button disabled={isUpdatePending} onClick={handleAssign}>
- {isUpdatePending && (
- <Loader className="mr-2 h-4 w-4 animate-spin" aria-hidden="true" />
- )}
- Assign
- </Button>
+ {activeTab === "assign" ? (
+ <Button
+ disabled={isUpdatePending || selectedUserIds.length === 0}
+ onClick={handleAssign}
+ >
+ {isUpdatePending && (
+ <Loader className="mr-2 h-4 w-4 animate-spin" aria-hidden="true" />
+ )}
+ <Plus className="mr-2 h-4 w-4" />
+ Assign ({selectedUserIds.length})
+ </Button>
+ ) : (
+ <Button
+ disabled={isUpdatePending || selectedUserIds.length === 0}
+ onClick={handleRemove}
+ variant="destructive"
+ >
+ {isUpdatePending && (
+ <Loader className="mr-2 h-4 w-4 animate-spin" aria-hidden="true" />
+ )}
+ <Minus className="mr-2 h-4 w-4" />
+ Remove ({selectedUserIds.length})
+ </Button>
+ )}
</SheetFooter>
</SheetContent>
</Sheet>