Skip to content

Commit

Permalink
chore: create new form and enable update of other parts
Browse files Browse the repository at this point in the history
  • Loading branch information
khalifan-kfan committed Apr 25, 2024
1 parent 139a106 commit d3f148b
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ import { ViewMonitoringFormsComponent } from './pages/view/view-monitoring-forms
path: '',
component: MonitoringPageComponent,
},
{
path: 'create',
component: UpdateMonitoringFormsComponent,
},
{
path: ':id',
component: ViewMonitoringFormsComponent,
Expand All @@ -27,7 +31,7 @@ import { ViewMonitoringFormsComponent } from './pages/view/view-monitoring-forms
{
path: ':id/edit',
component: UpdateMonitoringFormsComponent,
},
}
]),
],
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,23 @@ export class MonitoringFormsDashboardService extends PicsaAsyncService {
}
return data;
}

public async createForm(newForm: Partial<IMonitoringFormsRow>): Promise<IMonitoringFormsRow> {
newForm.id = this.generateId(newForm.title?newForm.title:null);
const { data, error } = await this.supabaseService.db
.table(this.TABLE_NAME)
.insert(newForm)
.single();
if (error) {
throw error;
}
return data;
}

// adopting this id genrating funtion
private generateId(title: string|null) {
const cleanedText = title?.toLowerCase().replace(/[^a-z ]/gi, '').replace(/\s+/g, '_');
return title ? cleanedText : ''
}
/**
* Convert an xls form to xml-xform standard
* @param file xls file representation
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<div class="page-content">
<div style="display: flex; align-items: center">
<div style="display: flex; align-items: center; flex-direction: row; justify-content: space-between;">
<h2 style="flex: 1">Monitoring Forms</h2>
<button mat-stroked-button color="primary" routerLink="create"><mat-icon>add</mat-icon>Add New Form</button>
</div>
@if(service.forms){
<picsa-data-table
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class MonitoringPageComponent implements OnInit {
'summary_fields',
'enketo_form',
'enketo_model',
'created_at',
'created_at'
];

constructor(public service: MonitoringFormsDashboardService, private router: Router, private route: ActivatedRoute) {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,42 @@
<div class="page-content">
<div style="display: flex; align-items: center">
@if(formID){
<h2 style="flex: 1">Update Form</h2>
} @else {
<h2 style="flex: 1">Add Form</h2>
}
</div>
@if(form){
<form class="form-content">
<h2 style="flex: 1">Upload new Form excel file</h2>
<picsa-supabase-upload
[fileTypes]="allowedFileTypes"
[autoUpload]="false"
[storageBucketName]="storageBucketName"
[storageFolderPath]="storageFolderPath"
(uploadComplete)="handleUploadComplete($event)"
>
</picsa-supabase-upload>
<form [formGroup]="fileForm" class="form-content">

<mat-form-field>
<mat-label>Title</mat-label>
<input type="text" matInput formControlName="title" style="text-align: start;" />
</mat-form-field>
<mat-form-field>
<mat-label>Description</mat-label>
<input type="text" matInput formControlName="description" style="text-align: start;" />
</mat-form-field>
<div>
<h2 style="flex: 1">Upload cover image (optional)</h2>
<picsa-supabase-upload [fileTypes]="allowedCoverTypes" [fileDropHeight]="128" [autoUpload]="true"
[storageBucketName]="storageBucketName" [storageFolderPath]="coverImageStorageFolder"
(uploadComplete)="handleCoverUploadComplete($event, 'cover_image')"></picsa-supabase-upload>
</div>

<div>
<h2 style="flex: 1">Upload new Form excel file</h2>
<picsa-supabase-upload [fileTypes]="allowedFileTypes" [autoUpload]="false" [storageBucketName]="storageBucketName"
[storageFolderPath]="storageFolderPath" (uploadComplete)="handleUploadComplete($event)">
</picsa-supabase-upload>
@if(convertXlsxFeedbackMessage) {
<div>{{ convertXlsxFeedbackMessage }}</div>
} @if(uploading===true) {
<div>Uploading form...</div>
}
</div>

<button mat-raised-button color="primary" (click)="handleSubmitForm()">{{loadingNewForm ? "saving..." : "Save Form"}}</button>

</form>
} @if(updateFeedbackMessage) {
<div>{{ updateFeedbackMessage }}</div>
} @if(uploading===true) {
<div>Uploading form...</div>
}
</div>

</div>
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { CommonModule } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { FormBuilder, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { ActivatedRoute, RouterModule } from '@angular/router';
import { Router } from '@angular/router';
// eslint-disable-next-line @nx/enforce-module-boundaries
import type { Database } from '@picsa/server-types';
import {
Expand Down Expand Up @@ -35,28 +36,57 @@ export type IMonitoringFormsRow = Database['public']['Tables']['monitoring_forms
})
export class UpdateMonitoringFormsComponent implements OnInit {
public form: IMonitoringFormsRow;
public updateFeedbackMessage = '';
public convertXlsxFeedbackMessage = '';
public uploading = false;
public allowedFileTypes = ['xlsx', 'xls'].map((ext) => `.${ext}`);
public allowedCoverTypes = ['jpg', 'jpeg', 'svg', 'png'].map((ext) => `.${ext}`);
public storageBucketName = 'global';
public storageFolderPath = 'monitoring/forms';
public coverImageStorageFolder = 'monitoring/cover_images';
public formID = null;
public xformConversionSuccess = false;
public loadingNewForm = false;

public fileForm = this.formBuilder.nonNullable.group({
title: ['', Validators.required],
description: ['', Validators.required],
cover_image: [''],
form_xlsx: [''],
enketo_form: [''],
enketo_model: [''],
enketo_definition: {},
});

constructor(
private service: MonitoringFormsDashboardService,
private route: ActivatedRoute,
private storageService: SupabaseStorageService
private storageService: SupabaseStorageService,
private formBuilder: FormBuilder,
private router: Router
) {}
async ngOnInit() {
await this.service.ready();
this.route.params.subscribe(async (params) => {
const id = params['id'];
this.service
.getFormById(id)
.then((data) => {
this.form = data;
})
.catch((error) => {
console.error('Error fetching Form:', error);
});
this.formID = params['id'];
if (this.formID) {
this.service
.getFormById(this.formID)
.then((data) => {
this.form = data;
this.fileForm.patchValue({
title: data.title ?? '', // Use empty string as a fallback if data.title is null
cover_image: data.cover_image ?? '',
description: data.description ?? '',
form_xlsx: data.form_xlsx ?? '',
enketo_form: data.enketo_form ?? '',
enketo_model: data.enketo_model ?? '',
enketo_definition: data.enketo_definition ?? {},
});
})
.catch((error) => {
console.error('Error fetching Form:', error);
});
}
});
}

Expand All @@ -66,7 +96,7 @@ export class UpdateMonitoringFormsComponent implements OnInit {
}
// As conversion is a 2-step process (xls file -> xml form -> enketo form) track progress
// so that uploaded file can be removed if not successful
let xformConversionSuccess = false;

this.uploading = true;
const [{ data, entry }] = res;

Expand All @@ -81,23 +111,64 @@ export class UpdateMonitoringFormsComponent implements OnInit {
const enketoContent = await this.service.submitFormToConvertXFormToEnketo(formData);
if (enketoContent) {
const { form, languageMap, model, theme } = enketoContent;
// Update db entry with form_xlsx
this.form = await this.service.updateFormById(this.form.id, {
this.fileForm.patchValue({
form_xlsx: `${this.storageBucketName}/${this.storageFolderPath}/${entry.name}`,
enketo_form: form,
enketo_model: model,
enketo_definition: { ...(this.form.enketo_definition as any), languageMap, theme },
enketo_definition: { ...languageMap, theme },
});
this.updateFeedbackMessage = 'Form updated successfully!';
this.convertXlsxFeedbackMessage = 'Form updated successfully!';
this.uploading = false;
xformConversionSuccess = true;
this.xformConversionSuccess = true;
}
}
// If conversion not successful delete file from storage
if (!xformConversionSuccess) {
if (!this.xformConversionSuccess) {
const storagePath = `${this.storageFolderPath}/${entry.name}`;
const { error } = await this.storageService.deleteFile(this.storageBucketName, storagePath);
if (error) throw error;
}
}

public async handleCoverUploadComplete(res: IUploadResult[], controlName: 'storage_file' | 'cover_image') {
if (res.length === 0) {
return;
}
const [{ entry }] = res;
this.fileForm.patchValue({
[controlName]: `${this.storageBucketName}/${this.coverImageStorageFolder}/${entry.name}`,
});
}
public async handleSubmitForm() {
const isUpdatingForm = !!this.formID;

this.loadingNewForm = true;

const values = this.fileForm.getRawValue();
if (!values.title) {
this.loadingNewForm = false;
return;
}
if (isUpdatingForm) {
const updatedValues = Object.fromEntries(Object.entries(values).filter(([key, value]) => value !== ''));
await this.service.updateFormById(this.form.id, updatedValues);
this.loadingNewForm = false;
this.router.navigate([`/monitoring/${this.form.id}`]);
return;
}

if (!this.xformConversionSuccess) {
this.convertXlsxFeedbackMessage = 'Please upload a new excel form to convert!';
this.loadingNewForm = false;
return;
}

if (!isUpdatingForm) {
await this.service.createForm(values);
this.loadingNewForm = false;
this.router.navigate([`/monitoring/${this.form.id}`]);
return;
}

}
}

0 comments on commit d3f148b

Please sign in to comment.