V13-FE-006: consolidate approved UI and contract hardening
This commit is contained in:
+29
@@ -0,0 +1,29 @@
|
||||
import type { KbxImportDefinition, KbxImportMapping } from '@kbx/contracts'
|
||||
|
||||
export type KbxImportMappingIssueCode = 'required-missing' | 'duplicate-target'
|
||||
export interface KbxImportMappingIssue {
|
||||
code: KbxImportMappingIssueCode
|
||||
fieldKey: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export function validateKbxImportMappings(definition:KbxImportDefinition,mappings:readonly KbxImportMapping[]):KbxImportMappingIssue[]{
|
||||
const fields=definition.fields.filter(field=>field.importable!==false)
|
||||
const targets=mappings.map(mapping=>mapping.targetField).filter((value):value is string=>Boolean(value))
|
||||
const issues:KbxImportMappingIssue[]=[]
|
||||
for(const target of [...new Set(targets.filter((value,index)=>targets.indexOf(value)!==index))]){
|
||||
const field=fields.find(item=>item.key===target)
|
||||
issues.push({code:'duplicate-target',fieldKey:target,message:`${field?.label ?? target} 필드에 Excel 열이 두 개 이상 연결되어 있습니다.`})
|
||||
}
|
||||
for(const field of fields.filter(item=>item.required)){
|
||||
if(!targets.includes(field.key))issues.push({code:'required-missing',fieldKey:field.key,message:`${field.label} 필수 필드를 매핑하세요.`})
|
||||
}
|
||||
return issues
|
||||
}
|
||||
|
||||
export function validateKbxImportFileCandidate(definition:KbxImportDefinition,file:{name:string;size:number}):string|null{
|
||||
if(!file.name.toLocaleLowerCase().endsWith('.xlsx'))return 'Excel .xlsx 파일만 업로드할 수 있습니다.'
|
||||
const maxBytes=definition.maxFileSizeBytes??10*1024*1024
|
||||
if(file.size>maxBytes)return `파일 크기는 ${Math.round(maxBytes/1048576)}MB 이하여야 합니다.`
|
||||
return null
|
||||
}
|
||||
Reference in New Issue
Block a user