@@ -6,11 +6,13 @@ import {
66 ButtonProps ,
77 CircularProgress ,
88 Stack ,
9+ Tab ,
910 Table ,
1011 TableBody ,
1112 TableCell ,
1213 TableHead ,
1314 TableRow ,
15+ Tabs ,
1416 Typography ,
1517} from "@mui/material" ;
1618import Form , { IChangeEvent } from "@rjsf/core" ;
@@ -88,6 +90,11 @@ const ReadOnlyValueField: React.FC<{
8890 return value as string ;
8991} ;
9092
93+ type InnerAdminEditorStateType = {
94+ tab : number ;
95+ formData : Record < string , string > | undefined ;
96+ } ;
97+
9198const InnerAdminEditor : React . FC < AppResourceIdType & AdminEditorPropsType > =
9299 ErrorBoundary . with (
93100 { fallback : Common . Components . ErrorFallback } ,
@@ -110,9 +117,11 @@ const InnerAdminEditor: React.FC<AppResourceIdType & AdminEditorPropsType> =
110117 RJSFSchema ,
111118 { [ k in string ] : unknown }
112119 > | null > ( null ) ;
113- const [ formDataState , setFormDataState ] = React . useState <
114- Record < string , string > | undefined
115- > ( undefined ) ;
120+ const [ editorState , setEditorState ] =
121+ React . useState < InnerAdminEditorStateType > ( {
122+ tab : 0 ,
123+ formData : undefined ,
124+ } ) ;
116125 const backendAdminClient =
117126 Common . Hooks . BackendAdminAPI . useBackendAdminClient ( ) ;
118127 const { data : schemaInfo } =
@@ -122,6 +131,13 @@ const InnerAdminEditor: React.FC<AppResourceIdType & AdminEditorPropsType> =
122131 resource
123132 ) ;
124133
134+ const setTab = ( _ : React . SyntheticEvent , selectedTab : number ) =>
135+ setEditorState ( ( ps ) => ( { ...ps , tab : selectedTab } ) ) ;
136+ const setFormDataState = ( formData ?: Record < string , string > ) =>
137+ setEditorState ( ( ps ) => ( { ...ps , formData } ) ) ;
138+ const selectedLanguage = editorState . tab === 0 ? "ko" : "en" ;
139+ const notSelectedLanguage = editorState . tab === 0 ? "en" : "ko" ;
140+
125141 const createMutation = Common . Hooks . BackendAdminAPI . useCreateMutation <
126142 Record < string , string >
127143 > ( backendAdminClient , app , resource ) ;
@@ -195,16 +211,40 @@ const InnerAdminEditor: React.FC<AppResourceIdType & AdminEditorPropsType> =
195211 const goToCreateNew = ( ) => navigate ( `/${ app } /${ resource } /create` ) ;
196212
197213 const writableSchema =
198- Common . Utils . filterWritablePropertiesInJsonSchema ( schemaInfo . schema ) ;
214+ Common . Utils . filterPropertiesByLanguageInJsonSchema (
215+ Common . Utils . filterWritablePropertiesInJsonSchema (
216+ schemaInfo . schema
217+ ) ,
218+ schemaInfo . translation_fields ,
219+ selectedLanguage
220+ ) ;
199221 const readOnlySchema =
200- Common . Utils . filterReadOnlyPropertiesInJsonSchema ( schemaInfo . schema ) ;
222+ Common . Utils . filterPropertiesByLanguageInJsonSchema (
223+ Common . Utils . filterReadOnlyPropertiesInJsonSchema (
224+ schemaInfo . schema
225+ ) ,
226+ schemaInfo . translation_fields ,
227+ selectedLanguage
228+ ) ;
201229 const uiSchema : UiSchema = schemaInfo . ui_schema ;
202230 const disabled =
203231 createMutation . isPending ||
204232 modifyMutation . isPending ||
205233 deleteMutation . isPending ;
206234 const title = `${ app . toUpperCase ( ) } > ${ resource . toUpperCase ( ) } > ${ id ? "편집: " + id : "새 객체 추가" } ` ;
207235
236+ const notSelectedLangFields = schemaInfo . translation_fields . map (
237+ ( f ) => `${ f } _${ notSelectedLanguage } `
238+ ) ;
239+ const languageFilteredFormData = editorState . formData
240+ ? Object . entries ( editorState . formData )
241+ . filter ( ( [ k ] ) => ! notSelectedLangFields . includes ( k ) )
242+ . reduce (
243+ ( acc , [ k , v ] ) => ( { ...acc , [ k ] : v } ) ,
244+ { } as Record < string , string >
245+ )
246+ : undefined ;
247+
208248 const handleCtrlSAction : (
209249 this : GlobalEventHandlers ,
210250 ev : KeyboardEvent
@@ -225,56 +265,75 @@ const InnerAdminEditor: React.FC<AppResourceIdType & AdminEditorPropsType> =
225265 } ;
226266 } , [ ] ) ;
227267
228- if ( formDataState === undefined ) return < CircularProgress /> ;
268+ if ( editorState . formData === undefined ) return < CircularProgress /> ;
229269
230270 return (
231271 < Box sx = { { flexGrow : 1 , width : "100%" , minHeight : "100%" } } >
232272 < Typography variant = "h5" > { title } </ Typography >
233- { id && (
234- < >
235- < Table >
236- < TableHead >
237- < TableRow >
238- < TableCell > 필드</ TableCell >
239- < TableCell > 값</ TableCell >
240- </ TableRow >
241- </ TableHead >
242- < TableBody >
243- { Object . keys ( readOnlySchema . properties || { } ) . map ( ( key ) => (
244- < TableRow key = { key } >
245- < TableCell > { key } </ TableCell >
246- < TableCell >
247- < ReadOnlyValueField
248- name = { key }
249- value = { formDataState ?. [ key ] }
250- uiSchema = { uiSchema }
251- />
252- </ TableCell >
253- </ TableRow >
254- ) ) }
255- </ TableBody >
256- </ Table >
257- < br />
258- </ >
259- ) }
260- < MuiForm
261- ref = { formRef }
262- schema = { writableSchema }
263- uiSchema = { {
264- ...uiSchema ,
265- "ui:submitButtonOptions" : { norender : true } ,
266- } }
267- validator = { customizeValidator ( { AjvClass : AjvDraft04 } ) }
268- formData = { formDataState }
269- liveValidate
270- focusOnFirstError
271- formContext = { { readonlyAsDisabled : true } }
272- onChange = { ( { formData } ) => setFormDataState ( formData ) }
273- onSubmit = { onSubmitFunc }
274- disabled = { disabled }
275- showErrorList = { false }
276- fields = { { file : FileField } }
277- />
273+ < Stack
274+ direction = "row"
275+ spacing = { 2 }
276+ sx = { { width : "100%" , height : "100%" , maxWidth : "100%" } }
277+ >
278+ < Tabs
279+ orientation = "vertical"
280+ value = { editorState . tab }
281+ onChange = { setTab }
282+ scrollButtons = { false }
283+ >
284+ < Tab wrapped label = "한국어" />
285+ < Tab wrapped label = "영어" />
286+ </ Tabs >
287+ < Box sx = { { flexGrow : 1 } } >
288+ { id && (
289+ < >
290+ < Table >
291+ < TableHead >
292+ < TableRow >
293+ < TableCell > 필드</ TableCell >
294+ < TableCell > 값</ TableCell >
295+ </ TableRow >
296+ </ TableHead >
297+ < TableBody >
298+ { Object . keys ( readOnlySchema . properties || { } ) . map (
299+ ( key ) => (
300+ < TableRow key = { key } >
301+ < TableCell > { key } </ TableCell >
302+ < TableCell >
303+ < ReadOnlyValueField
304+ name = { key }
305+ value = { languageFilteredFormData ?. [ key ] }
306+ uiSchema = { uiSchema }
307+ />
308+ </ TableCell >
309+ </ TableRow >
310+ )
311+ ) }
312+ </ TableBody >
313+ </ Table >
314+ < br />
315+ </ >
316+ ) }
317+ < MuiForm
318+ ref = { formRef }
319+ schema = { writableSchema }
320+ uiSchema = { {
321+ ...uiSchema ,
322+ "ui:submitButtonOptions" : { norender : true } ,
323+ } }
324+ validator = { customizeValidator ( { AjvClass : AjvDraft04 } ) }
325+ formData = { languageFilteredFormData }
326+ liveValidate
327+ focusOnFirstError
328+ formContext = { { readonlyAsDisabled : true } }
329+ onChange = { ( { formData } ) => setFormDataState ( formData ) }
330+ onSubmit = { onSubmitFunc }
331+ disabled = { disabled }
332+ showErrorList = { false }
333+ fields = { { file : FileField } }
334+ />
335+ </ Box >
336+ </ Stack >
278337 { children }
279338 < Stack
280339 direction = "row"
0 commit comments