Skip to content

Commit

Permalink
Add temporary function to append sample questions to a form, just to …
Browse files Browse the repository at this point in the history
…test the display of form fields. Will add in edit UI next, to remove the need for this.
  • Loading branch information
danielnaab committed Jan 5, 2024
1 parent 37b1b30 commit 4b316a0
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 30 deletions.
31 changes: 30 additions & 1 deletion apps/spotlight/src/components/react/form/edit.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,44 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { getFormFromStorage } from '../../../lib/form-repo';
import { getFormFromStorage, saveFormToStorage } from '../../../lib/form-repo';
import { addQuestions } from '@atj/forms';

export const FormEdit = ({ formId }: { formId: string }) => {
const form = getFormFromStorage(window.localStorage, formId);
if (!form) {
return 'Form not found';
}
return (
<div>
<h1>Edit form interface</h1>
<div>Editing form {formId}</div>
<code>{JSON.stringify(form)}</code>
<ul>
<li>
<button
className="usa-button usa-button--unstyled"
onClick={() => {
const newForm = addQuestions(form, [
{
id: 'question-1',
text: 'Test question',
initial: 'initial value',
required: true,
},
{
id: 'question-2',
text: 'Test question 2',
initial: 'initial value 2',
required: true,
},
]);
saveFormToStorage(window.localStorage, formId, newForm);
window.location.reload();
}}
>
***Append sample form fields***
</button>
</li>
<li>
<Link to={`/${formId}`}>View form</Link>
</li>
Expand Down
8 changes: 4 additions & 4 deletions apps/spotlight/src/components/react/form/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import { useNavigate, Link } from 'react-router-dom';

import {
addFormToStorage,
addFormSummaryToStorage,
getFormListFromStorage,
} from '../../../lib/form-repo';

Expand All @@ -14,8 +14,8 @@ export const FormList = () => {
<ul className="usa-list usa-list--unstyled">
{formIds.map((formId, index) => (
<li key={index}>
{formId}
<Link to={`/${formId}/edit`}>Edit</Link>
{formId} <Link to={`/${formId}`}>View</Link> /{' '}
<Link to={`/${formId}/edit`}>Edit</Link> /{' '}
<Link to={`/${formId}/delete`}>Delete</Link>
</li>
))}
Expand All @@ -32,7 +32,7 @@ export const FormList = () => {
console.error('required fields not found');
return;
}
const result = addFormToStorage(window.localStorage, {
const result = addFormSummaryToStorage(window.localStorage, {
title,
description,
});
Expand Down
5 changes: 3 additions & 2 deletions apps/spotlight/src/components/react/form/view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
UnorderedList,
} from './fields';
import { getFormFromStorage } from '../../../lib/form-repo';
import { createFormContext } from '@atj/forms';
import { createFormContext, createPrompt } from '@atj/forms';

// Assuming this is the structure of your JSON data
export interface Field {
Expand All @@ -39,7 +39,8 @@ export const FormView = ({ formId }: { formId: string }) => {
return 'null form retrieved from storage';
}
const context = createFormContext(form);
return <FormFieldset fields={form.questions} />;
const prompt = createPrompt(context);
return <FormFieldset fields={prompt} />;
};

export const FormFieldset = ({ fields }: { fields: Field[] }) => {
Expand Down
28 changes: 20 additions & 8 deletions apps/spotlight/src/lib/form-repo.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import { FormSummary, createForm } from '@atj/forms/src';
import formData from '../htmlParser/ud105-form-field-output.json';
import { Form, FormSummary, createForm } from '@atj/forms/src';

export const getFormFromStorage = (storage: Storage, id?: string) => {
export const getFormFromStorage = (
storage: Storage,
id?: string
): Form | null => {
if (!storage || !id) {
return null;
}
const formString = storage.getItem(id);
if (!formString) {
// FIXME: hardcode something for now
if (id === 'hardcoded-form-id') {
return formData;
}
return null;
}
return JSON.parse(formString);
Expand All @@ -25,7 +23,10 @@ export const getFormListFromStorage = (storage: Storage) => {
return keys;
};

export const addFormToStorage = (storage: Storage, summary: FormSummary) => {
export const addFormSummaryToStorage = (
storage: Storage,
summary: FormSummary
) => {
const form = createForm(summary);
const uuid = crypto.randomUUID();
storage.setItem(uuid, JSON.stringify(form));
Expand All @@ -35,6 +36,17 @@ export const addFormToStorage = (storage: Storage, summary: FormSummary) => {
};
};

export const saveFormToStorage = (
storage: Storage,
formId: string,
form: Form
) => {
storage.setItem(formId, JSON.stringify(form));
return {
success: true,
};
};

export const deleteFormFromStorage = (storage: Storage, formId: string) => {
storage.removeItem(formId);
};
5 changes: 1 addition & 4 deletions apps/spotlight/src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import ContentLayout from '../layouts/ContentLayout.astro';
<h1>10x Access to Justice Spotlight</h1>
<ul>
<li>
<a
href="https://trello.com/c/25Jl6NwJ/207-digital-access-to-justice-platform"
>Project overview</a
>
<a href={`${import.meta.env.BASE_URL}forms`}>Manage my forms</a>
</li>
<li>
<a href={`${import.meta.env.BASE_URL}form-sample`}>Sample form</a>
Expand Down
64 changes: 57 additions & 7 deletions packages/forms/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ export type FormSummary = {
description: string;
};

export type Form = {
export type Form<T extends FormStrategy> = {
summary: FormSummary;
questions: Record<QuestionId, Question>;
strategy: SequentialStrategy;
strategy: T;
};

export type FormContext = {
Expand All @@ -34,17 +34,19 @@ export type SequentialStrategy = {
order: QuestionId[];
};

export type NullStrategy = {
type: 'null';
};

export type FormStrategy = SequentialStrategy | NullStrategy;

export const createForm = (
summary: FormSummary,
questions: Question[] = []
): Form => {
return {
summary,
questions: Object.fromEntries(
questions.map(question => {
return [question.id, question];
})
),
questions: getQuestionMap(questions),
strategy: {
type: 'sequential',
order: questions.map(question => {
Expand All @@ -68,6 +70,31 @@ export const createFormContext = (form: Form): FormContext => {
};
};

// For now, a prompt just returns an array of questions. This will likely need
// to be filled out to support more complicated display formats.
export const createPrompt = (formContext: FormContext) => {
if (formContext.form.strategy.type === 'sequential') {
return formContext.form.strategy.order.map(questionId => {
const question = formContext.form.questions[questionId];
// This is the structure currently used by FormFieldset in the Astro app.
// FIXME: Shore up this type and add to the forms package.
return {
tag: 'input',
type: 'text',
name: question.id,
id: question.id,
value: formContext.context.values[questionId],
label: question.text,
};
});
} else if (formContext.form.strategy.type === 'null') {
return [];
} else {
const _exhaustiveCheck: never = formContext.form.strategy;
return _exhaustiveCheck;
}
};

export const updateForm = (
context: FormContext,
id: QuestionId,
Expand Down Expand Up @@ -113,3 +140,26 @@ const addError = (
},
},
});

const getQuestionMap = (questions: Question[]) => {
return Object.fromEntries(
questions.map(question => {
return [question.id, question];
})
);
};

export const addQuestions = (
form: Form<SequentialStrategy>,
questions: Question[]
) => {
const questionMap = getQuestionMap(questions);
return {
...form,
questions: { ...form.questions, ...questionMap },
strategy: {
...form.strategy,
order: [...form.strategy.order, ...Object.keys(questionMap)],
},
};
};
8 changes: 4 additions & 4 deletions packages/forms/tests/two-field-form.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ describe('two question form context', () => {

it('empty field value on required field is stored with error', () => {
const context = forms.createFormContext(form);
const nextForm = forms.updateForm(context, questions[0].id, null);
expect(nextForm).toEqual({
const nextContext = forms.updateForm(context, questions[0].id, null);
expect(nextContext).toEqual({
...context,
context: {
errors: {
Expand All @@ -49,12 +49,12 @@ describe('two question form context', () => {

it('valid field value is stored on context', () => {
const formContext = forms.createFormContext(form);
const nextForm = forms.updateForm(
const nextContext = forms.updateForm(
formContext,
questions[0].id,
'supercalifragilisticexpialidocious'
);
expect(nextForm).toEqual({
expect(nextContext).toEqual({
...formContext,
context: {
errors: {},
Expand Down

0 comments on commit 4b316a0

Please sign in to comment.