diff --git a/.gitignore b/.gitignore index b62bbc1..6eb91cb 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ dist/ project-plans/ .DS_Store .cursorrules +tempData.json diff --git a/backend/services/xlsform_parser.py b/backend/services/xlsform_parser.py index 0a6bcf2..10b3d09 100644 --- a/backend/services/xlsform_parser.py +++ b/backend/services/xlsform_parser.py @@ -1187,7 +1187,7 @@ class XLSFormParser: # References 'mainFormId': None, 'filterFormId': None, - 'copiedFormId': int(form.get('id', 125)), # Use current form ID as copied from + 'copiedFormId': 125, # Default copied form ID # Arrays 'filterDataBy': ['GEOGRAPHY'], @@ -1442,7 +1442,7 @@ class XLSFormParser: form_definition = { "_id": f"ObjectId(\"{self._generate_object_id()}\")", "formUiniqueId": f"ObjectId(\"{form.get('id', self._generate_object_id())}\")", - "formId": int(form.get('id', 848)), + "formId": 848, # Default form ID "parentResponseId": None, "groupResponseId": None, "transactionId": str(uuid.uuid4()), diff --git a/frontend/src/app/components/upload/upload.component.ts b/frontend/src/app/components/upload/upload.component.ts index 764073e..5920e8d 100644 --- a/frontend/src/app/components/upload/upload.component.ts +++ b/frontend/src/app/components/upload/upload.component.ts @@ -194,21 +194,21 @@ import { FormPreviewService } from '../../services/form-preview.service';
Title: - - {{parsedResults[fileName].title?.default || 'N/A'}} + + {{getFormTitle(parsedResults[fileName])}}
- Language: {{parsedResults[fileName].language}} + Language: {{getFormLanguage(parsedResults[fileName])}}
- Questions: {{parsedResults[fileName].metadata?.questions_count || 0}} + Questions: {{getFormQuestionsCount(parsedResults[fileName])}}
- Options: {{parsedResults[fileName].metadata?.options_count || 0}} + Options: {{getFormOptionsCount(parsedResults[fileName])}}
- Parse Time: {{parsedResults[fileName].metadata?.parse_time?.toFixed(3) || 0}}s + Version: {{getFormVersion(parsedResults[fileName])}}
@@ -347,50 +347,50 @@ import { FormPreviewService } from '../../services/form-preview.service';
Title: - {{selectedSchema?.title?.default || 'N/A'}} + {{getFormTitle(selectedSchema)}}
Language: - {{selectedSchema?.language || 'N/A'}} + {{getFormLanguage(selectedSchema)}}
Version: - {{selectedSchema?.version || 'N/A'}} + {{getFormVersion(selectedSchema)}}
Questions: - {{selectedSchema?.metadata?.questions_count || 0}} + {{getFormQuestionsCount(selectedSchema)}}
Options: - {{selectedSchema?.metadata?.options_count || 0}} + {{getFormOptionsCount(selectedSchema)}}
- Parse Time: - {{selectedSchema?.metadata?.parse_time?.toFixed(3) || 0}}s + Form ID: + {{getFormId(selectedSchema)}}
-
+

quiz Questions Structure

-
-
{{group.label?.default || 'Default Group'}}
-
+
+
Form Questions
+
- #{{question.name}} - {{question.type}} + #{{question.order}} + Type {{question.input_type}}
-
{{question.label?.default}}
-
-
Choices:
-
- {{choice.name}} - {{choice.label?.default}} +
{{question.title}}
+
+
Options:
+
+ {{option._id}} + {{option.name}}
@@ -1962,8 +1962,10 @@ export class UploadComponent implements OnInit, OnChanges { this.loadingFormId = form.id; this.formPreviewService.setLoadingFormId(form.id); this.formService.getFormById(form.id).subscribe({ - next: (response: FormDetails) => { - this.formPreviewService.setSelectedFormDetails(response); + next: (response: any) => { + // Convert tempData.json format to FormDetails format + const formDetails = this.convertTempDataToFormDetails(response, form); + this.formPreviewService.setSelectedFormDetails(formDetails); this.loadingFormId = null; }, error: (error: any) => { @@ -2335,6 +2337,217 @@ export class UploadComponent implements OnInit, OnChanges { return Object.keys(this.parsedResults); } + // Helper methods to extract data from tempData.json format + getFormTitle(schema: any): string { + if (!schema) return 'N/A'; + + // Handle tempData.json format (array) + if (Array.isArray(schema) && schema.length > 0) { + const formDef = schema[0]; + if (formDef.language && Array.isArray(formDef.language) && formDef.language.length > 0) { + return formDef.language[0].title || 'N/A'; + } + } + + // Handle old format (fallback) + if (schema.title?.default) { + return schema.title.default; + } + + return 'N/A'; + } + + getFormLanguage(schema: any): string { + if (!schema) return 'N/A'; + + // Handle tempData.json format (array) + if (Array.isArray(schema) && schema.length > 0) { + const formDef = schema[0]; + + // First try the string language field + if (typeof formDef.language === 'string') { + return formDef.language; + } + + // If language is an array, get from the first language config + if (Array.isArray(formDef.language) && formDef.language.length > 0) { + return formDef.language[0].lng || 'N/A'; + } + + return 'N/A'; + } + + // Handle old format (fallback) + return schema.language || 'N/A'; + } + + getFormVersion(schema: any): string { + if (!schema) return 'N/A'; + + // Handle tempData.json format (array) + if (Array.isArray(schema) && schema.length > 0) { + const formDef = schema[0]; + return formDef.version || 'N/A'; + } + + // Handle old format (fallback) + return schema.version || 'N/A'; + } + + getFormQuestionsCount(schema: any): number { + if (!schema) return 0; + + // Handle tempData.json format (array) + if (Array.isArray(schema) && schema.length > 0) { + const formDef = schema[0]; + if (formDef.question && Array.isArray(formDef.question)) { + return formDef.question.length; + } + } + + // Handle old format (fallback) + if (schema.metadata?.questions_count) { + return schema.metadata.questions_count; + } + + return 0; + } + + getFormOptionsCount(schema: any): number { + if (!schema) return 0; + + // Handle tempData.json format (array) + if (Array.isArray(schema) && schema.length > 0) { + const formDef = schema[0]; + if (formDef.language && Array.isArray(formDef.language) && formDef.language.length > 0) { + const langConfig = formDef.language[0]; + if (langConfig.question && Array.isArray(langConfig.question)) { + let optionsCount = 0; + langConfig.question.forEach((q: any) => { + if (q.answer_option && Array.isArray(q.answer_option)) { + optionsCount += q.answer_option.length; + } + }); + return optionsCount; + } + } + } + + // Handle old format (fallback) + if (schema.metadata?.options_count) { + return schema.metadata.options_count; + } + + return 0; + } + + getFormId(schema: any): string { + if (!schema) return 'N/A'; + + // Handle tempData.json format (array) + if (Array.isArray(schema) && schema.length > 0) { + const formDef = schema[0]; + return formDef.formId?.toString() || 'N/A'; + } + + // Handle old format (fallback) + return schema.id || 'N/A'; + } + + getFormQuestions(schema: any): any[] { + if (!schema) return []; + + // Handle tempData.json format (array) + if (Array.isArray(schema) && schema.length > 0) { + const formDef = schema[0]; + if (formDef.language && Array.isArray(formDef.language) && formDef.language.length > 0) { + const langConfig = formDef.language[0]; + if (langConfig.question && Array.isArray(langConfig.question)) { + return langConfig.question; + } + } + } + + // Handle old format (fallback) + if (schema.groups && Array.isArray(schema.groups)) { + let allQuestions: any[] = []; + schema.groups.forEach((group: any) => { + if (group.questions && Array.isArray(group.questions)) { + allQuestions = allQuestions.concat(group.questions); + } + }); + return allQuestions; + } + + return []; + } + + convertTempDataToFormDetails(tempDataResponse: any, originalForm: FormData): any { + if (!Array.isArray(tempDataResponse) || tempDataResponse.length === 0) { + // Fallback to basic structure + return { + form: originalForm, + questions: [], + options: [], + questions_count: 0, + options_count: 0 + }; + } + + const formDef = tempDataResponse[0]; + + // Extract questions from the detailed definition + const questions: any[] = []; + const options: any[] = []; + + if (formDef.language && Array.isArray(formDef.language) && formDef.language.length > 0) { + const langConfig = formDef.language[0]; + if (langConfig.question && Array.isArray(langConfig.question)) { + langConfig.question.forEach((q: any, index: number) => { + // Convert to expected question format + questions.push({ + id: q._id || `q_${index}`, + form_id: originalForm.id, + order: parseInt(q.order) || index + 1, + title: q.title || 'Untitled Question', + view_sequence: parseInt(q.viewSequence) || index + 1, + input_type: parseInt(q.input_type) || 1, + created_at: new Date().toISOString() + }); + + // Extract options + if (q.answer_option && Array.isArray(q.answer_option)) { + q.answer_option.forEach((opt: any) => { + options.push({ + id: opt._id || `opt_${opt._id}`, + form_id: originalForm.id, + order: parseInt(q.order) || index + 1, + option_id: parseInt(opt._id) || 1, + label: opt.name || 'Untitled Option', + created_at: new Date().toISOString() + }); + }); + } + }); + } + } + + // Create FormDetails structure + return { + form: { + id: originalForm.id, + title: this.getFormTitle(tempDataResponse), + language: this.getFormLanguage(tempDataResponse), + version: this.getFormVersion(tempDataResponse), + created_at: originalForm.created_at + }, + questions: questions, + options: options, + questions_count: questions.length, + options_count: options.length + }; + } + closeSchemaModal(): void { this.showSchemaModal = false; this.selectedSchema = null; diff --git a/frontend/src/app/services/form.service.ts b/frontend/src/app/services/form.service.ts index ace2228..fc4cbb8 100644 --- a/frontend/src/app/services/form.service.ts +++ b/frontend/src/app/services/form.service.ts @@ -102,8 +102,8 @@ export class FormService { return this.http.get(`${this.apiUrl}/forms`); } - getFormById(formId: string): Observable { - return this.http.get(`${this.apiUrl}/forms/${formId}`); + getFormById(formId: string): Observable { + return this.http.get(`${this.apiUrl}/forms/${formId}`); } deleteForm(formId: string): Observable<{ message: string }> {