UNPKG

@restnfeel/agentc-starter-kit

Version:

한국어 기업용 CMS 모듈 - Task Master AI와 함께 빠르게 웹사이트를 구현할 수 있는 재사용 가능한 컴포넌트 시스템

640 lines (564 loc) 16.7 kB
"use client"; import { useState, useEffect, useCallback } from "react"; import { UserProfile, CreateUserRequest, UpdateUserRequest, UserListFilters, UserListSort, PaginationParams, UserListResponse, UserStats, BulkUserOperation, BulkOperationResult, PasswordResetRequest, PasswordResetConfirm, EmailVerificationRequest, EmailVerificationConfirm, ProfileUpdateRequest, } from "./types"; // 사용자 목록 관리 훅 export function useUsers(initialFilters: UserListFilters = {}) { const [users, setUsers] = useState<UserProfile[]>([]); const [loading, setLoading] = useState(true); const [error, setError] = useState<string | null>(null); const [filters, setFilters] = useState<UserListFilters>(initialFilters); const [sort, setSort] = useState<UserListSort>({ field: "createdAt", direction: "desc", }); const [pagination, setPagination] = useState<PaginationParams>({ page: 1, limit: 20, }); const [totalPages, setTotalPages] = useState(0); const [total, setTotal] = useState(0); const fetchUsers = useCallback(async () => { try { setLoading(true); setError(null); const queryParams = new URLSearchParams({ page: pagination.page.toString(), limit: pagination.limit.toString(), sortField: sort.field, sortDirection: sort.direction, ...Object.fromEntries( Object.entries(filters).filter( ([, value]) => value !== undefined && value !== "" ) ), }); const response = await fetch(`/api/users?${queryParams}`); if (!response.ok) { throw new Error("사용자 목록을 불러오는데 실패했습니다"); } const data: UserListResponse = await response.json(); setUsers(data.users); setTotal(data.pagination.total); setTotalPages(data.pagination.totalPages); } catch (err) { setError( err instanceof Error ? err.message : "알 수 없는 오류가 발생했습니다" ); } finally { setLoading(false); } }, [filters, sort, pagination]); useEffect(() => { fetchUsers(); }, [fetchUsers]); const updateFilters = useCallback((newFilters: Partial<UserListFilters>) => { setFilters((prev) => ({ ...prev, ...newFilters })); setPagination((prev) => ({ ...prev, page: 1 })); // 필터 변경 시 첫 페이지로 }, []); const updateSort = useCallback((field: UserListSort["field"]) => { setSort((prev) => ({ field, direction: prev.field === field && prev.direction === "asc" ? "desc" : "asc", })); setPagination((prev) => ({ ...prev, page: 1 })); // 정렬 변경 시 첫 페이지로 }, []); const updatePagination = useCallback( (newPagination: Partial<PaginationParams>) => { setPagination((prev) => ({ ...prev, ...newPagination })); }, [] ); const refresh = useCallback(() => { fetchUsers(); }, [fetchUsers]); return { users, loading, error, filters, sort, pagination: { ...pagination, total, totalPages }, updateFilters, updateSort, updatePagination, refresh, }; } // 개별 사용자 관리 훅 export function useUser(userId?: string) { const [user, setUser] = useState<UserProfile | null>(null); const [loading, setLoading] = useState(false); const [error, setError] = useState<string | null>(null); const fetchUser = useCallback( async ( id: string, options: { includeTenant?: boolean; includeStats?: boolean } = {} ) => { try { setLoading(true); setError(null); const queryParams = new URLSearchParams(); if (options.includeTenant) queryParams.set("includeTenant", "true"); if (options.includeStats) queryParams.set("includeStats", "true"); const response = await fetch(`/api/users/${id}?${queryParams}`); if (!response.ok) { if (response.status === 404) { throw new Error("사용자를 찾을 수 없습니다"); } throw new Error("사용자 정보를 불러오는데 실패했습니다"); } const userData = await response.json(); setUser(userData); return userData; } catch (err) { setError( err instanceof Error ? err.message : "알 수 없는 오류가 발생했습니다" ); throw err; } finally { setLoading(false); } }, [] ); useEffect(() => { if (userId) { fetchUser(userId); } }, [userId, fetchUser]); return { user, loading, error, fetchUser, setUser, }; } // 사용자 생성 훅 export function useCreateUser() { const [loading, setLoading] = useState(false); const [error, setError] = useState<string | null>(null); const createUser = useCallback( async (userData: CreateUserRequest): Promise<UserProfile> => { try { setLoading(true); setError(null); const response = await fetch("/api/users", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(userData), }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "사용자 생성에 실패했습니다"); } const newUser = await response.json(); return newUser; } catch (err) { const errorMessage = err instanceof Error ? err.message : "사용자 생성 중 오류가 발생했습니다"; setError(errorMessage); throw new Error(errorMessage); } finally { setLoading(false); } }, [] ); return { createUser, loading, error, }; } // 사용자 업데이트 훅 export function useUpdateUser() { const [loading, setLoading] = useState(false); const [error, setError] = useState<string | null>(null); const updateUser = useCallback( async ( userId: string, userData: UpdateUserRequest ): Promise<UserProfile> => { try { setLoading(true); setError(null); const response = await fetch(`/api/users/${userId}`, { method: "PUT", headers: { "Content-Type": "application/json", }, body: JSON.stringify(userData), }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "사용자 업데이트에 실패했습니다"); } const updatedUser = await response.json(); return updatedUser; } catch (err) { const errorMessage = err instanceof Error ? err.message : "사용자 업데이트 중 오류가 발생했습니다"; setError(errorMessage); throw new Error(errorMessage); } finally { setLoading(false); } }, [] ); return { updateUser, loading, error, }; } // 사용자 삭제 훅 export function useDeleteUser() { const [loading, setLoading] = useState(false); const [error, setError] = useState<string | null>(null); const deleteUser = useCallback(async (userId: string): Promise<void> => { try { setLoading(true); setError(null); const response = await fetch(`/api/users/${userId}`, { method: "DELETE", }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "사용자 삭제에 실패했습니다"); } } catch (err) { const errorMessage = err instanceof Error ? err.message : "사용자 삭제 중 오류가 발생했습니다"; setError(errorMessage); throw new Error(errorMessage); } finally { setLoading(false); } }, []); return { deleteUser, loading, error, }; } // 사용자 통계 훅 export function useUserStats() { const [stats, setStats] = useState<UserStats | null>(null); const [loading, setLoading] = useState(true); const [error, setError] = useState<string | null>(null); const fetchStats = useCallback(async () => { try { setLoading(true); setError(null); const response = await fetch("/api/users/stats"); if (!response.ok) { throw new Error("사용자 통계를 불러오는데 실패했습니다"); } const statsData = await response.json(); setStats(statsData); } catch (err) { setError( err instanceof Error ? err.message : "알 수 없는 오류가 발생했습니다" ); } finally { setLoading(false); } }, []); useEffect(() => { fetchStats(); }, [fetchStats]); return { stats, loading, error, refresh: fetchStats, }; } // 대량 사용자 작업 훅 export function useBulkUserOperation() { const [loading, setLoading] = useState(false); const [error, setError] = useState<string | null>(null); const executeBulkOperation = useCallback( async (operation: BulkUserOperation): Promise<BulkOperationResult> => { try { setLoading(true); setError(null); const response = await fetch("/api/users/bulk", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(operation), }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "대량 작업에 실패했습니다"); } const result = await response.json(); return result; } catch (err) { const errorMessage = err instanceof Error ? err.message : "대량 작업 중 오류가 발생했습니다"; setError(errorMessage); throw new Error(errorMessage); } finally { setLoading(false); } }, [] ); return { executeBulkOperation, loading, error, }; } // 비밀번호 재설정 훅 export function usePasswordReset() { const [loading, setLoading] = useState(false); const [error, setError] = useState<string | null>(null); const requestPasswordReset = useCallback( async (data: PasswordResetRequest): Promise<void> => { try { setLoading(true); setError(null); const response = await fetch("/api/auth/password-reset/request", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(data), }); if (!response.ok) { const errorData = await response.json(); throw new Error( errorData.error || "비밀번호 재설정 요청에 실패했습니다" ); } } catch (err) { const errorMessage = err instanceof Error ? err.message : "비밀번호 재설정 요청 중 오류가 발생했습니다"; setError(errorMessage); throw new Error(errorMessage); } finally { setLoading(false); } }, [] ); const confirmPasswordReset = useCallback( async (data: PasswordResetConfirm): Promise<void> => { try { setLoading(true); setError(null); const response = await fetch("/api/auth/password-reset/confirm", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(data), }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "비밀번호 재설정에 실패했습니다"); } } catch (err) { const errorMessage = err instanceof Error ? err.message : "비밀번호 재설정 중 오류가 발생했습니다"; setError(errorMessage); throw new Error(errorMessage); } finally { setLoading(false); } }, [] ); return { requestPasswordReset, confirmPasswordReset, loading, error, }; } // 이메일 인증 훅 export function useEmailVerification() { const [loading, setLoading] = useState(false); const [error, setError] = useState<string | null>(null); const requestEmailVerification = useCallback( async (data: EmailVerificationRequest): Promise<void> => { try { setLoading(true); setError(null); const response = await fetch("/api/auth/email-verification/request", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(data), }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "이메일 인증 요청에 실패했습니다"); } } catch (err) { const errorMessage = err instanceof Error ? err.message : "이메일 인증 요청 중 오류가 발생했습니다"; setError(errorMessage); throw new Error(errorMessage); } finally { setLoading(false); } }, [] ); const confirmEmailVerification = useCallback( async (data: EmailVerificationConfirm): Promise<void> => { try { setLoading(true); setError(null); const response = await fetch("/api/auth/email-verification/confirm", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(data), }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "이메일 인증에 실패했습니다"); } } catch (err) { const errorMessage = err instanceof Error ? err.message : "이메일 인증 중 오류가 발생했습니다"; setError(errorMessage); throw new Error(errorMessage); } finally { setLoading(false); } }, [] ); return { requestEmailVerification, confirmEmailVerification, loading, error, }; } // 프로필 업데이트 훅 export function useProfileUpdate() { const [loading, setLoading] = useState(false); const [error, setError] = useState<string | null>(null); const updateProfile = useCallback( async (data: ProfileUpdateRequest): Promise<UserProfile> => { try { setLoading(true); setError(null); const response = await fetch("/api/auth/profile", { method: "PUT", headers: { "Content-Type": "application/json", }, body: JSON.stringify(data), }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "프로필 업데이트에 실패했습니다"); } const updatedProfile = await response.json(); return updatedProfile; } catch (err) { const errorMessage = err instanceof Error ? err.message : "프로필 업데이트 중 오류가 발생했습니다"; setError(errorMessage); throw new Error(errorMessage); } finally { setLoading(false); } }, [] ); return { updateProfile, loading, error, }; } // 계정 잠금 해제 훅 export function useAccountUnlock() { const [loading, setLoading] = useState(false); const [error, setError] = useState<string | null>(null); const unlockAccount = useCallback( async (userId: string, reason?: string): Promise<void> => { try { setLoading(true); setError(null); const response = await fetch("/api/users/unlock", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ userId, reason }), }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "계정 잠금 해제에 실패했습니다"); } } catch (err) { const errorMessage = err instanceof Error ? err.message : "계정 잠금 해제 중 오류가 발생했습니다"; setError(errorMessage); throw new Error(errorMessage); } finally { setLoading(false); } }, [] ); return { unlockAccount, loading, error, }; }