summaryrefslogtreecommitdiff
path: root/lib/vendor-document-list/ship/import-from-dolce-button.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vendor-document-list/ship/import-from-dolce-button.tsx')
-rw-r--r--lib/vendor-document-list/ship/import-from-dolce-button.tsx152
1 files changed, 78 insertions, 74 deletions
diff --git a/lib/vendor-document-list/ship/import-from-dolce-button.tsx b/lib/vendor-document-list/ship/import-from-dolce-button.tsx
index 90796d8e..1ffe466d 100644
--- a/lib/vendor-document-list/ship/import-from-dolce-button.tsx
+++ b/lib/vendor-document-list/ship/import-from-dolce-button.tsx
@@ -25,6 +25,8 @@ import { SimplifiedDocumentsView } from "@/db/schema"
import { ImportStatus } from "../import-service"
import { useSession } from "next-auth/react"
import { getProjectIdsByVendor } from "../service"
+import { useParams } from "next/navigation"
+import { useTranslation } from "@/i18n/client"
// ๐Ÿ”ฅ API ์‘๋‹ต ์บ์‹œ (์ปดํฌ๋„ŒํŠธ ์™ธ๋ถ€์— ์„ ์–ธํ•˜์—ฌ ์ธ์Šคํ„ด์Šค ๊ฐ„ ๊ณต์œ )
const statusCache = new Map<string, { data: ImportStatus; timestamp: number }>()
@@ -69,6 +71,10 @@ export function ImportFromDOLCEButton({
const { data: session } = useSession()
const vendorId = session?.user.companyId
+ const params = useParams()
+ const lng = (params?.lng as string) || "ko"
+ const { t } = useTranslation(lng, "engineering")
+
// ๐Ÿ”ฅ allDocuments์—์„œ projectIds ์ถ”์ถœ (props๋กœ ์ „๋‹ฌ๋ฐ›์€ ๊ฒฝ์šฐ ์‚ฌ์šฉ)
const documentsProjectIds = React.useMemo(() => {
if (propProjectIds) return propProjectIds // props๋กœ ๋ฐ›์€ ๊ฒฝ์šฐ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ
@@ -182,44 +188,34 @@ export function ImportFromDOLCEButton({
} catch (error) {
console.error('Failed to fetch import statuses:', error)
- toast.error('Unable to check status. Please verify project settings.')
+ toast.error(t('dolceImport.messages.statusCheckError'))
} finally {
setStatusLoading(false)
}
- }, [debouncedProjectIds, fetchImportStatusCached])
+ }, [debouncedProjectIds, fetchImportStatusCached, t])
// ๐Ÿ”ฅ vendorId๋กœ projects ๊ฐ€์ ธ์˜ค๊ธฐ (์ตœ์ ํ™”)
React.useEffect(() => {
- let isCancelled = false
-
- const fetchVendorProjects = async () => {
- if (allDocuments.length === 0 && vendorId && !loadingVendorProjects) {
- setLoadingVendorProjects(true)
- try {
- const projectIds = await getProjectIdsByVendor(vendorId)
- if (!isCancelled) {
- setVendorProjectIds(projectIds)
- }
- } catch (error) {
- console.error('Failed to fetch vendor projects:', error)
- if (!isCancelled) {
- toast.error('Failed to fetch project information.')
- }
- } finally {
- if (!isCancelled) {
- setLoadingVendorProjects(false)
- }
- }
- }
- }
-
- fetchVendorProjects()
-
- return () => {
- isCancelled = true
- }
- }, [allDocuments.length, vendorId, loadingVendorProjects])
-
+ let isCancelled = false;
+
+ if (allDocuments.length !== 0 || !vendorId) return;
+
+ setLoadingVendorProjects(true);
+
+ getProjectIdsByVendor(vendorId)
+ .then((projectIds) => {
+ if (!isCancelled) setVendorProjectIds(projectIds);
+ })
+ .catch((error) => {
+ if (!isCancelled) toast.error(t('dolceImport.messages.projectFetchError'));
+ })
+ .finally(() => {
+ if (!isCancelled) setLoadingVendorProjects(false);
+ });
+
+ return () => { isCancelled = true; };
+ }, [allDocuments, vendorId, t]);
+
// ๐Ÿ”ฅ ์ปดํฌ๋„ŒํŠธ ๋งˆ์šดํŠธ ์‹œ ์ƒํƒœ ์กฐํšŒ (๋””๋ฐ”์šด์‹ฑ ์ ์šฉ)
React.useEffect(() => {
if (debouncedProjectIds.length > 0) {
@@ -314,16 +310,21 @@ export function ImportFromDOLCEButton({
if (totalResult.success) {
toast.success(
- `DOLCE import completed`,
+ t('dolceImport.messages.importSuccess'),
{
- description: `New ${totalResult.newCount}, Updated ${totalResult.updatedCount}, Skipped ${totalResult.skippedCount} (${projectIds.length} projects)`
+ description: t('dolceImport.messages.importSuccessDescription', {
+ newCount: totalResult.newCount,
+ updatedCount: totalResult.updatedCount,
+ skippedCount: totalResult.skippedCount,
+ projectCount: projectIds.length
+ })
}
)
} else {
toast.error(
- `DOLCE import partially failed`,
+ t('dolceImport.messages.importPartiallyFailed'),
{
- description: 'Some projects failed to import.'
+ description: t('dolceImport.messages.importPartiallyFailedDescription')
}
)
}
@@ -338,35 +339,35 @@ export function ImportFromDOLCEButton({
setImportProgress(0)
setIsImporting(false)
- toast.error('DOLCE import failed', {
- description: error instanceof Error ? error.message : 'An unknown error occurred.'
+ toast.error(t('dolceImport.messages.importFailed'), {
+ description: error instanceof Error ? error.message : t('dolceImport.messages.unknownError')
})
}
- }, [projectIds, fetchAllImportStatus, onImportComplete])
+ }, [projectIds, fetchAllImportStatus, onImportComplete, t])
// ๐Ÿ”ฅ ์ƒํƒœ ๋ฑƒ์ง€ ๋ฉ”๋ชจ์ด์ œ์ด์…˜
const statusBadge = React.useMemo(() => {
if (loadingVendorProjects) {
- return <Badge variant="secondary">Loading project information...</Badge>
+ return <Badge variant="secondary">{t('dolceImport.status.loadingProjectInfo')}</Badge>
}
if (statusLoading) {
- return <Badge variant="secondary">Checking DOLCE connection...</Badge>
+ return <Badge variant="secondary">{t('dolceImport.status.checkingConnection')}</Badge>
}
if (importStatusMap.size === 0) {
- return <Badge variant="destructive">DOLCE Connection Error</Badge>
+ return <Badge variant="destructive">{t('dolceImport.status.connectionError')}</Badge>
}
if (!totalStats.importEnabled) {
- return <Badge variant="secondary">DOLCE Import Disabled</Badge>
+ return <Badge variant="secondary">{t('dolceImport.status.importDisabled')}</Badge>
}
if (totalStats.newDocuments > 0 || totalStats.updatedDocuments > 0) {
return (
<Badge variant="samsung" className="gap-1">
<AlertTriangle className="w-3 h-3" />
- Updates Available ({projectIds.length} projects)
+ {t('dolceImport.status.updatesAvailable', { projectCount: projectIds.length })}
</Badge>
)
}
@@ -374,10 +375,10 @@ export function ImportFromDOLCEButton({
return (
<Badge variant="default" className="gap-1 bg-green-500 hover:bg-green-600">
<CheckCircle className="w-3 h-3" />
- Synchronized with DOLCE
+ {t('dolceImport.status.synchronized')}
</Badge>
)
- }, [loadingVendorProjects, statusLoading, importStatusMap.size, totalStats, projectIds.length])
+ }, [loadingVendorProjects, statusLoading, importStatusMap.size, totalStats, projectIds.length, t])
const canImport = totalStats.importEnabled &&
(totalStats.newDocuments > 0 || totalStats.updatedDocuments > 0)
@@ -389,7 +390,7 @@ export function ImportFromDOLCEButton({
}, [fetchAllImportStatus])
// ๋กœ๋”ฉ ์ค‘์ด๊ฑฐ๋‚˜ projectIds๊ฐ€ ์—†์œผ๋ฉด ๋ฒ„ํŠผ์„ ํ‘œ์‹œํ•˜์ง€ ์•Š์Œ
- if (loadingVendorProjects || projectIds.length === 0) {
+ if (projectIds.length === 0) {
return null
}
@@ -409,7 +410,7 @@ export function ImportFromDOLCEButton({
) : (
<Download className="w-4 h-4" />
)}
- <span className="hidden sm:inline">Get List</span>
+ <span className="hidden sm:inline">{t('dolceImport.buttons.getList')}</span>
{totalStats.newDocuments + totalStats.updatedDocuments > 0 && (
<Badge
variant="samsung"
@@ -425,9 +426,9 @@ export function ImportFromDOLCEButton({
<PopoverContent className="w-96">
<div className="space-y-4">
<div className="space-y-2">
- <h4 className="font-medium">DOLCE Import Status</h4>
+ <h4 className="font-medium">{t('dolceImport.labels.importStatus')}</h4>
<div className="flex items-center justify-between">
- <span className="text-sm text-muted-foreground">Current Status</span>
+ <span className="text-sm text-muted-foreground">{t('dolceImport.labels.currentStatus')}</span>
{statusBadge}
</div>
</div>
@@ -435,17 +436,17 @@ export function ImportFromDOLCEButton({
{/* ํ”„๋กœ์ ํŠธ ์†Œ์Šค ํ‘œ์‹œ */}
{allDocuments.length === 0 && vendorProjectIds.length > 0 && (
<div className="text-xs text-blue-600 bg-blue-50 p-2 rounded">
- No documents found, importing from all projects.
+ {t('dolceImport.descriptions.noDocumentsImportAll')}
</div>
)}
{/* ๋‹ค์ค‘ ํ”„๋กœ์ ํŠธ ์ •๋ณด ํ‘œ์‹œ */}
{projectIds.length > 1 && (
<div className="text-sm">
- <div className="text-muted-foreground">Target Projects</div>
- <div className="font-medium">{projectIds.length} projects</div>
+ <div className="text-muted-foreground">{t('dolceImport.labels.targetProjects')}</div>
+ <div className="font-medium">{t('dolceImport.labels.projectCount', { count: projectIds.length })}</div>
<div className="text-xs text-muted-foreground">
- Project IDs: {projectIds.join(', ')}
+ {t('dolceImport.labels.projectIds')}: {projectIds.join(', ')}
</div>
</div>
)}
@@ -456,17 +457,17 @@ export function ImportFromDOLCEButton({
<div className="grid grid-cols-2 gap-4 text-sm">
<div>
- <div className="text-muted-foreground">New Documents</div>
+ <div className="text-muted-foreground">{t('dolceImport.labels.newDocuments')}</div>
<div className="font-medium">{totalStats.newDocuments || 0}</div>
</div>
<div>
- <div className="text-muted-foreground">Updates</div>
+ <div className="text-muted-foreground">{t('dolceImport.labels.updates')}</div>
<div className="font-medium">{totalStats.updatedDocuments || 0}</div>
</div>
</div>
<div className="text-sm">
- <div className="text-muted-foreground">Total Documents (B3/B4/B5)</div>
+ <div className="text-muted-foreground">{t('dolceImport.labels.totalDocuments')}</div>
<div className="font-medium">{totalStats.availableDocuments || 0}</div>
</div>
@@ -474,20 +475,23 @@ export function ImportFromDOLCEButton({
{projectIds.length > 1 && (
<details className="text-sm">
<summary className="cursor-pointer text-muted-foreground hover:text-foreground">
- Details by Project
+ {t('dolceImport.labels.detailsByProject')}
</summary>
<div className="mt-2 space-y-2 pl-2 border-l-2 border-muted">
{projectIds.map(projectId => {
const status = importStatusMap.get(projectId)
return (
<div key={projectId} className="text-xs">
- <div className="font-medium">Project {projectId}</div>
+ <div className="font-medium">{t('dolceImport.labels.projectLabel', { projectId })}</div>
{status ? (
<div className="text-muted-foreground">
- New {status.newDocuments}, Updates {status.updatedDocuments}
+ {t('dolceImport.descriptions.projectDetails', {
+ newDocuments: status.newDocuments,
+ updatedDocuments: status.updatedDocuments
+ })}
</div>
) : (
- <div className="text-destructive">Status check failed</div>
+ <div className="text-destructive">{t('dolceImport.status.statusCheckFailed')}</div>
)}
</div>
)
@@ -510,12 +514,12 @@ export function ImportFromDOLCEButton({
{isImporting ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
- Importing...
+ {t('dolceImport.buttons.importing')}
</>
) : (
<>
<Download className="w-4 h-4 mr-2" />
- Import Now
+ {t('dolceImport.buttons.importNow')}
</>
)}
</Button>
@@ -541,10 +545,10 @@ export function ImportFromDOLCEButton({
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
- <DialogTitle>Import Document List from DOLCE</DialogTitle>
+ <DialogTitle>{t('dolceImport.dialog.title')}</DialogTitle>
<DialogDescription>
- Import the latest document list from Samsung Heavy Industries DOLCE system.
- {projectIds.length > 1 && ` (${projectIds.length} projects targeted)`}
+ {t('dolceImport.dialog.description')}
+ {projectIds.length > 1 && ` (${t('dolceImport.dialog.multipleProjects', { count: projectIds.length })})`}
</DialogDescription>
</DialogHeader>
@@ -552,20 +556,20 @@ export function ImportFromDOLCEButton({
{totalStats && (
<div className="rounded-lg border p-4 space-y-3">
<div className="flex items-center justify-between text-sm">
- <span>Items to Import</span>
+ <span>{t('dolceImport.labels.itemsToImport')}</span>
<span className="font-medium">
{totalStats.newDocuments + totalStats.updatedDocuments}
</span>
</div>
<div className="text-xs text-muted-foreground">
- Includes new and updated documents (B3, B4, B5).
+ {t('dolceImport.descriptions.includesNewAndUpdated')}
<br />
- For B4 documents, GTTPreDwg and GTTWorkingDwg issue stages will be auto-generated.
+ {t('dolceImport.descriptions.b4DocumentsNote')}
{projectIds.length > 1 && (
<>
<br />
- Will import sequentially from {projectIds.length} projects.
+ {t('dolceImport.descriptions.sequentialImport', { count: projectIds.length })}
</>
)}
</div>
@@ -573,7 +577,7 @@ export function ImportFromDOLCEButton({
{isImporting && (
<div className="space-y-2">
<div className="flex items-center justify-between text-sm">
- <span>Progress</span>
+ <span>{t('dolceImport.labels.progress')}</span>
<span>{importProgress}%</span>
</div>
<Progress value={importProgress} className="h-2" />
@@ -588,7 +592,7 @@ export function ImportFromDOLCEButton({
onClick={() => setIsDialogOpen(false)}
disabled={isImporting}
>
- Cancel
+ {t('buttons.cancel')}
</Button>
<Button
onClick={handleImport}
@@ -597,12 +601,12 @@ export function ImportFromDOLCEButton({
{isImporting ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
- Importing...
+ {t('dolceImport.buttons.importing')}
</>
) : (
<>
<Download className="w-4 h-4 mr-2" />
- Start Import
+ {t('dolceImport.buttons.startImport')}
</>
)}
</Button>