diff options
Diffstat (limited to 'lib/vendor-regular-registrations/table/vendor-regular-registrations-table-toolbar-actions.tsx')
| -rw-r--r-- | lib/vendor-regular-registrations/table/vendor-regular-registrations-table-toolbar-actions.tsx | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/lib/vendor-regular-registrations/table/vendor-regular-registrations-table-toolbar-actions.tsx b/lib/vendor-regular-registrations/table/vendor-regular-registrations-table-toolbar-actions.tsx new file mode 100644 index 00000000..c3b4739a --- /dev/null +++ b/lib/vendor-regular-registrations/table/vendor-regular-registrations-table-toolbar-actions.tsx @@ -0,0 +1,248 @@ +"use client"
+
+import { type Table } from "@tanstack/react-table"
+import { toast } from "sonner"
+
+import { Button } from "@/components/ui/button"
+import { FileText, RefreshCw, Download, Mail, FileWarning, Scale, Shield } from "lucide-react"
+import type { VendorRegularRegistration } from "@/config/vendorRegularRegistrationsColumnsConfig"
+import {
+ sendMissingContractRequestEmails,
+ sendAdditionalInfoRequestEmails,
+ skipLegalReview,
+ skipSafetyQualification
+} from "../service"
+import { useState } from "react"
+import { SkipReasonDialog } from "@/components/vendor-regular-registrations/skip-reason-dialog"
+
+interface VendorRegularRegistrationsTableToolbarActionsProps {
+ table: Table<VendorRegularRegistration>
+}
+
+export function VendorRegularRegistrationsTableToolbarActions({
+ table,
+}: VendorRegularRegistrationsTableToolbarActionsProps) {
+ const [syncLoading, setSyncLoading] = useState<{
+ missingContract: boolean;
+ additionalInfo: boolean;
+ legalSkip: boolean;
+ safetySkip: boolean;
+ }>({
+ missingContract: false,
+ additionalInfo: false,
+ legalSkip: false,
+ safetySkip: false,
+ })
+
+ const [skipDialogs, setSkipDialogs] = useState<{
+ legalReview: boolean;
+ safetyQualification: boolean;
+ }>({
+ legalReview: false,
+ safetyQualification: false,
+ })
+
+ const selectedRows = table.getFilteredSelectedRowModel().rows.map(row => row.original)
+
+
+
+ const handleSendMissingContractRequest = async () => {
+ if (selectedRows.length === 0) {
+ toast.error("이메일을 발송할 업체를 선택해주세요.")
+ return
+ }
+
+ setSyncLoading(prev => ({ ...prev, missingContract: true }))
+ try {
+ const vendorIds = selectedRows.map(row => row.vendorId)
+ const result = await sendMissingContractRequestEmails(vendorIds)
+
+ if (result.success) {
+ toast.success(result.message)
+ } else {
+ toast.error(result.error)
+ }
+ } catch (error) {
+ console.error("Error sending missing contract request:", error)
+ toast.error("누락계약요청 이메일 발송 중 오류가 발생했습니다.")
+ } finally {
+ setSyncLoading(prev => ({ ...prev, missingContract: false }))
+ }
+ }
+
+ const handleSendAdditionalInfoRequest = async () => {
+ if (selectedRows.length === 0) {
+ toast.error("이메일을 발송할 업체를 선택해주세요.")
+ return
+ }
+
+ setSyncLoading(prev => ({ ...prev, additionalInfo: true }))
+ try {
+ const vendorIds = selectedRows.map(row => row.vendorId)
+ const result = await sendAdditionalInfoRequestEmails(vendorIds)
+
+ if (result.success) {
+ toast.success(result.message)
+ } else {
+ toast.error(result.error)
+ }
+ } catch (error) {
+ console.error("Error sending additional info request:", error)
+ toast.error("추가정보요청 이메일 발송 중 오류가 발생했습니다.")
+ } finally {
+ setSyncLoading(prev => ({ ...prev, additionalInfo: false }))
+ }
+ }
+
+ const handleLegalReviewSkip = async (reason: string) => {
+ const cpReviewRows = selectedRows.filter(row => row.status === "cp_review");
+ if (cpReviewRows.length === 0) {
+ toast.error("CP검토 상태인 업체를 선택해주세요.");
+ return;
+ }
+
+ setSyncLoading(prev => ({ ...prev, legalSkip: true }));
+ try {
+ const vendorIds = cpReviewRows.map(row => row.vendorId);
+ const result = await skipLegalReview(vendorIds, reason);
+
+ if (result.success) {
+ toast.success(result.message);
+ window.location.reload();
+ } else {
+ toast.error(result.error);
+ }
+ } catch (error) {
+ console.error("Error skipping legal review:", error);
+ toast.error("법무검토 Skip 처리 중 오류가 발생했습니다.");
+ } finally {
+ setSyncLoading(prev => ({ ...prev, legalSkip: false }));
+ }
+ };
+
+ const handleSafetyQualificationSkip = async (reason: string) => {
+ if (selectedRows.length === 0) {
+ toast.error("업체를 선택해주세요.");
+ return;
+ }
+
+ setSyncLoading(prev => ({ ...prev, safetySkip: true }));
+ try {
+ const vendorIds = selectedRows.map(row => row.vendorId);
+ const result = await skipSafetyQualification(vendorIds, reason);
+
+ if (result.success) {
+ toast.success(result.message);
+ window.location.reload();
+ } else {
+ toast.error(result.error);
+ }
+ } catch (error) {
+ console.error("Error skipping safety qualification:", error);
+ toast.error("안전적격성평가 Skip 처리 중 오류가 발생했습니다.");
+ } finally {
+ setSyncLoading(prev => ({ ...prev, safetySkip: false }));
+ }
+ };
+
+ // CP검토 상태인 선택된 행들 개수
+ const cpReviewCount = selectedRows.filter(row => row.status === "cp_review").length;
+
+ return (
+ <div className="flex items-center gap-2">
+ {/* <Button
+ variant="outline"
+ size="sm"
+ onClick={handleSyncDocuments}
+ disabled={syncLoading.documents || selectedRows.length === 0}
+ >
+ <FileText className="mr-2 h-4 w-4" />
+ {syncLoading.documents ? "동기화 중..." : "문서 동기화"}
+ </Button>
+
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={handleSyncAgreements}
+ disabled={syncLoading.agreements || selectedRows.length === 0}
+ >
+ <RefreshCw className="mr-2 h-4 w-4" />
+ {syncLoading.agreements ? "동기화 중..." : "계약 동기화"}
+ </Button> */}
+
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={handleSendMissingContractRequest}
+ disabled={syncLoading.missingContract || selectedRows.length === 0}
+ >
+ <FileWarning className="mr-2 h-4 w-4" />
+ {syncLoading.missingContract ? "발송 중..." : "누락계약요청"}
+ </Button>
+
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={handleSendAdditionalInfoRequest}
+ disabled={syncLoading.additionalInfo || selectedRows.length === 0}
+ >
+ <Mail className="mr-2 h-4 w-4" />
+ {syncLoading.additionalInfo ? "발송 중..." : "추가정보요청"}
+ </Button>
+
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={() => {
+ if (selectedRows.length === 0) {
+ toast.error("내보낼 항목을 선택해주세요.")
+ return
+ }
+ toast.info("엑셀 내보내기 기능은 준비 중입니다.")
+ }}
+ disabled={selectedRows.length === 0}
+ >
+ <Download className="mr-2 h-4 w-4" />
+ 엑셀 내보내기
+ </Button>
+
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={() => setSkipDialogs(prev => ({ ...prev, legalReview: true }))}
+ disabled={syncLoading.legalSkip || cpReviewCount === 0}
+ >
+ <Scale className="mr-2 h-4 w-4" />
+ {syncLoading.legalSkip ? "처리 중..." : "법무검토 Skip"}
+ </Button>
+
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={() => setSkipDialogs(prev => ({ ...prev, safetyQualification: true }))}
+ disabled={syncLoading.safetySkip || selectedRows.length === 0}
+ >
+ <Shield className="mr-2 h-4 w-4" />
+ {syncLoading.safetySkip ? "처리 중..." : "안전 Skip"}
+ </Button>
+
+ <SkipReasonDialog
+ open={skipDialogs.legalReview}
+ onOpenChange={(open) => setSkipDialogs(prev => ({ ...prev, legalReview: open }))}
+ title="법무검토 Skip"
+ description={`선택된 ${cpReviewCount}개 업체의 법무검토를 Skip하고 CP완료 상태로 변경합니다. Skip 사유를 입력해주세요.`}
+ onConfirm={handleLegalReviewSkip}
+ loading={syncLoading.legalSkip}
+ />
+
+ <SkipReasonDialog
+ open={skipDialogs.safetyQualification}
+ onOpenChange={(open) => setSkipDialogs(prev => ({ ...prev, safetyQualification: open }))}
+ title="안전적격성평가 Skip"
+ description={`선택된 ${selectedRows.length}개 업체의 안전적격성평가를 Skip하고 완료 상태로 변경합니다. Skip 사유를 입력해주세요.`}
+ onConfirm={handleSafetyQualificationSkip}
+ loading={syncLoading.safetySkip}
+ />
+ </div>
+ )
+}
|
