summaryrefslogtreecommitdiff
path: root/lib/tech-vendors/table
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-10-23 03:30:01 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-10-23 03:30:01 +0000
commitc8cccaf1198ae48754ac036b579732018f5b448a (patch)
tree9c64024818c2be1c7b6699b4e141729432719d86 /lib/tech-vendors/table
parent835010104c25c370c1def1f2de52f518058f8b46 (diff)
(최겸) 기술영업 조선 rfq 수정(벤더, 담당자 임시삭제기능 추가)
Diffstat (limited to 'lib/tech-vendors/table')
-rw-r--r--lib/tech-vendors/table/add-vendor-dialog.tsx13
-rw-r--r--lib/tech-vendors/table/delete-tech-vendors-dialog.tsx80
-rw-r--r--lib/tech-vendors/table/import-button.tsx19
-rw-r--r--lib/tech-vendors/table/tech-vendors-table-columns.tsx12
-rw-r--r--lib/tech-vendors/table/tech-vendors-table.tsx7
-rw-r--r--lib/tech-vendors/table/update-vendor-sheet.tsx13
6 files changed, 132 insertions, 12 deletions
diff --git a/lib/tech-vendors/table/add-vendor-dialog.tsx b/lib/tech-vendors/table/add-vendor-dialog.tsx
index e89f5d6b..f696b30a 100644
--- a/lib/tech-vendors/table/add-vendor-dialog.tsx
+++ b/lib/tech-vendors/table/add-vendor-dialog.tsx
@@ -30,6 +30,7 @@ import { Textarea } from "@/components/ui/textarea"
import { Plus, Loader2 } from "lucide-react"
import { addTechVendor } from "../service"
+import { normalizeEmailFields } from "../utils"
// 폼 스키마 정의
const addVendorSchema = z.object({
@@ -92,6 +93,13 @@ export function AddVendorDialog({ onSuccess }: AddVendorDialogProps) {
const onSubmit = async (data: AddVendorFormData) => {
setIsLoading(true)
try {
+ // 이메일 필드들을 소문자로 변환
+ const normalizedEmails = normalizeEmailFields({
+ email: data.email,
+ agentEmail: data.agentEmail,
+ representativeEmail: data.representativeEmail,
+ })
+
const result = await addTechVendor({
...data,
vendorCode: data.vendorCode || null,
@@ -100,13 +108,14 @@ export function AddVendorDialog({ onSuccess }: AddVendorDialogProps) {
countryFab: data.countryFab || null,
agentName: data.agentName || null,
agentPhone: data.agentPhone || null,
- agentEmail: data.agentEmail || null,
+ agentEmail: normalizedEmails.agentEmail,
address: data.address || null,
phone: data.phone || null,
website: data.website || null,
+ email: normalizedEmails.email,
techVendorType: data.techVendorType.join(','),
representativeName: data.representativeName || null,
- representativeEmail: data.representativeEmail || null,
+ representativeEmail: normalizedEmails.representativeEmail,
representativePhone: data.representativePhone || null,
representativeBirth: data.representativeBirth || null,
taxId: data.taxId || "",
diff --git a/lib/tech-vendors/table/delete-tech-vendors-dialog.tsx b/lib/tech-vendors/table/delete-tech-vendors-dialog.tsx
new file mode 100644
index 00000000..4fd3f32a
--- /dev/null
+++ b/lib/tech-vendors/table/delete-tech-vendors-dialog.tsx
@@ -0,0 +1,80 @@
+"use client"
+
+import * as React from "react"
+import { toast } from "sonner"
+import { Trash2 } from "lucide-react"
+
+import { Button } from "@/components/ui/button"
+import {
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogTitle,
+ AlertDialogTrigger,
+} from "@/components/ui/alert-dialog"
+
+import { deleteTechVendor } from "../service"
+import type { TechVendor } from "@/db/schema/techVendors"
+
+interface DeleteTechVendorDialogProps {
+ vendor: TechVendor
+ onSuccess?: () => void
+}
+// 임시 삭제 버튼
+export function DeleteTechVendorDialog({ vendor, onSuccess }: DeleteTechVendorDialogProps) {
+ const [isDeleting, setIsDeleting] = React.useState(false)
+
+ const handleDelete = async () => {
+ setIsDeleting(true)
+ try {
+ const result = await deleteTechVendor(vendor.id)
+
+ if (result.success) {
+ toast.success("벤더가 성공적으로 삭제되었습니다.")
+ onSuccess?.()
+ } else {
+ toast.error(result.error || "벤더 삭제 중 오류가 발생했습니다.")
+ }
+ } catch (error) {
+ console.error("벤더 삭제 오류:", error)
+ toast.error("벤더 삭제 중 오류가 발생했습니다.")
+ } finally {
+ setIsDeleting(false)
+ }
+ }
+
+ return (
+ <AlertDialog>
+ <AlertDialogTrigger asChild>
+ <Button variant="ghost" size="sm" className="text-red-600 hover:text-red-700 hover:bg-red-50">
+ <Trash2 className="size-4 mr-2" />
+ 삭제
+ </Button>
+ </AlertDialogTrigger>
+ <AlertDialogContent>
+ <AlertDialogHeader>
+ <AlertDialogTitle>벤더 삭제</AlertDialogTitle>
+ <AlertDialogDescription>
+ <strong>{vendor.vendorName}</strong> 벤더를 정말 삭제하시겠습니까?
+ <br />
+ 이 작업은 되돌릴 수 없으며, 관련된 모든 데이터(담당자, 아이템 등)가 함께 삭제됩니다.
+ </AlertDialogDescription>
+ </AlertDialogHeader>
+ <AlertDialogFooter>
+ <AlertDialogCancel>취소</AlertDialogCancel>
+ <AlertDialogAction
+ onClick={handleDelete}
+ disabled={isDeleting}
+ className="bg-red-600 hover:bg-red-700"
+ >
+ {isDeleting ? "삭제 중..." : "삭제"}
+ </AlertDialogAction>
+ </AlertDialogFooter>
+ </AlertDialogContent>
+ </AlertDialog>
+ )
+}
diff --git a/lib/tech-vendors/table/import-button.tsx b/lib/tech-vendors/table/import-button.tsx
index 85b16bc7..e0f95195 100644
--- a/lib/tech-vendors/table/import-button.tsx
+++ b/lib/tech-vendors/table/import-button.tsx
@@ -17,6 +17,7 @@ import {
import { Progress } from "@/components/ui/progress"
import { importTechVendorsFromExcel } from "../service"
import { decryptWithServerAction } from "@/components/drm/drmUtils"
+import { normalizeEmail } from "../utils"
interface ImportTechVendorButtonProps {
onSuccess?: () => void;
@@ -192,13 +193,17 @@ export function ImportTechVendorButton({ onSuccess }: ImportTechVendorButtonProp
// 벤더 데이터 처리
const vendors = dataRows.map(row => {
- const vendorEmail = row["이메일"] || row["email"] || "";
+ // 이메일들을 소문자로 변환
+ const vendorEmail = normalizeEmail(row["이메일"] || row["email"]) || null;
+ const contactEmail = normalizeEmail(row["담당자이메일"] || row["contactEmail"]);
+ const agentEmail = normalizeEmail(row["에이전트이메일"] || row["agentEmail"]);
+ const representativeEmail = normalizeEmail(row["대표자이메일"] || row["representativeEmail"]);
+
const contactName = row["담당자명"] || row["contactName"] || "";
- const contactEmail = row["담당자이메일"] || row["contactEmail"] || "";
-
+
// 담당자 정보 처리: 담당자가 없으면 벤더 이메일을 기본 담당자로 사용
const contacts = [];
-
+
if (contactName && contactEmail) {
// 명시적인 담당자가 있는 경우
contacts.push({
@@ -221,7 +226,7 @@ export function ImportTechVendorButton({ onSuccess }: ImportTechVendorButtonProp
isPrimary: true
});
}
-
+
return {
vendorName: row["업체명"] || row["vendorName"] || "",
vendorCode: row["업체코드"] || row["vendorCode"] || null,
@@ -232,13 +237,13 @@ export function ImportTechVendorButton({ onSuccess }: ImportTechVendorButtonProp
countryFab: row["제조국"] || row["countryFab"] || null,
agentName: row["에이전트명"] || row["agentName"] || null,
agentPhone: row["에이전트연락처"] || row["agentPhone"] || null,
- agentEmail: row["에이전트이메일"] || row["agentEmail"] || null,
+ agentEmail: agentEmail,
address: row["주소"] || row["address"] || null,
phone: row["전화번호"] || row["phone"] || null,
website: row["웹사이트"] || row["website"] || null,
techVendorType: row["벤더타입"] || row["techVendorType"] || "",
representativeName: row["대표자명"] || row["representativeName"] || null,
- representativeEmail: row["대표자이메일"] || row["representativeEmail"] || null,
+ representativeEmail: representativeEmail,
representativePhone: row["대표자연락처"] || row["representativePhone"] || null,
representativeBirth: row["대표자생년월일"] || row["representativeBirth"] || null,
items: row["아이템"] || row["items"] || "",
diff --git a/lib/tech-vendors/table/tech-vendors-table-columns.tsx b/lib/tech-vendors/table/tech-vendors-table-columns.tsx
index da17a975..c1bf6229 100644
--- a/lib/tech-vendors/table/tech-vendors-table-columns.tsx
+++ b/lib/tech-vendors/table/tech-vendors-table-columns.tsx
@@ -30,6 +30,7 @@ import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-
import { techVendorColumnsConfig } from "@/config/techVendorColumnsConfig"
import { Separator } from "@/components/ui/separator"
import { getVendorStatusIcon } from "../utils"
+import { DeleteTechVendorDialog } from "./delete-tech-vendors-dialog"
// 타입 정의 추가
type StatusType = (typeof techVendors.status.enumValues)[number];
@@ -47,6 +48,7 @@ type NextRouter = ReturnType<typeof useRouter>;
interface GetColumnsProps {
setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<TechVendor> | null>>;
router: NextRouter;
+ onVendorDeleted?: () => void;
}
@@ -55,7 +57,7 @@ interface GetColumnsProps {
/**
* tanstack table 컬럼 정의 (중첩 헤더 버전)
*/
-export function getColumns({ setRowAction, router }: GetColumnsProps): ColumnDef<TechVendor>[] {
+export function getColumns({ setRowAction, router, onVendorDeleted }: GetColumnsProps): ColumnDef<TechVendor>[] {
// ----------------------------------------------------------------
// 1) select 컬럼 (체크박스)
// ----------------------------------------------------------------
@@ -169,6 +171,14 @@ export function getColumns({ setRowAction, router }: GetColumnsProps): ColumnDef
</DropdownMenuSubContent>
</DropdownMenuSub>
+ <Separator />
+ {/* 벤더 임시 삭제 버튼 */}
+ <div className="px-2 py-1">
+ <DeleteTechVendorDialog
+ vendor={row.original}
+ onSuccess={onVendorDeleted}
+ />
+ </div>
</DropdownMenuContent>
</DropdownMenu>
diff --git a/lib/tech-vendors/table/tech-vendors-table.tsx b/lib/tech-vendors/table/tech-vendors-table.tsx
index 553ff109..e432a453 100644
--- a/lib/tech-vendors/table/tech-vendors-table.tsx
+++ b/lib/tech-vendors/table/tech-vendors-table.tsx
@@ -58,8 +58,13 @@ export function TechVendorsTable({
const router = useRouter()
// getColumns() 호출 시, router를 주입
+ // 임시 삭제 버튼 추가
const columns = React.useMemo(
- () => getColumns({ setRowAction, router }),
+ () => getColumns({
+ setRowAction,
+ router,
+ onVendorDeleted: () => router.refresh()
+ }),
[setRowAction, router]
)
diff --git a/lib/tech-vendors/table/update-vendor-sheet.tsx b/lib/tech-vendors/table/update-vendor-sheet.tsx
index 8498df51..3cbb2ba3 100644
--- a/lib/tech-vendors/table/update-vendor-sheet.tsx
+++ b/lib/tech-vendors/table/update-vendor-sheet.tsx
@@ -45,6 +45,7 @@ import { useSession } from "next-auth/react"
import { TechVendor, techVendors } from "@/db/schema/techVendors"
import { updateTechVendorSchema, type UpdateTechVendorSchema } from "../validations"
import { modifyTechVendor } from "../service"
+import { normalizeEmailFields } from "../utils"
interface UpdateVendorSheetProps
extends React.ComponentPropsWithRef<typeof Sheet> {
@@ -186,12 +187,22 @@ export function UpdateVendorSheet({ vendor, ...props }: UpdateVendorSheetProps)
? `상태 변경: ${getStatusConfig(oldStatus).label} → ${getStatusConfig(newStatus).label}`
: "" // Empty string instead of undefined
+ // 이메일 필드들을 소문자로 변환
+ const normalizedEmails = normalizeEmailFields({
+ email: data.email,
+ agentEmail: data.agentEmail,
+ representativeEmail: data.representativeEmail,
+ })
+
// 업체 정보 업데이트 - userId와 상태 변경 코멘트 추가
- const { error } = await modifyTechVendor({
+ const { error } = await modifyTechVendor({
id: String(vendor.id),
userId: Number(session.user.id), // Add user ID from session
comment: statusComment, // Add comment for status changes
...data, // 모든 데이터 전달 - 서비스 함수에서 필요한 필드만 처리
+ email: normalizedEmails.email || undefined,
+ agentEmail: normalizedEmails.agentEmail || undefined,
+ representativeEmail: normalizedEmails.representativeEmail || undefined,
techVendorType: Array.isArray(data.techVendorType) ? data.techVendorType.join(',') : undefined,
})