ui teaks and subject_id added

This commit is contained in:
Adriano Caloiaro 2025-01-22 08:54:40 -07:00
parent 4120bf4d5e
commit da68ab121a
No known key found for this signature in database
GPG key ID: C2BC56DE73CE3F75
8 changed files with 50 additions and 28 deletions

View file

@ -12,6 +12,7 @@ CREATE TABLE IF NOT EXISTS form_submissions (
id BIGINT PRIMARY KEY DEFAULT nextval('submission_ids'),
form_id BIGINT REFERENCES forms(id) ON DELETE CASCADE,
workspace_id TEXT NOT NULL,
subject_id TEXT,
fields jsonb default '{}' NOT NULL,
status submission_status default 'partial' NOT NULL,
created_at timestamptz not null default timezone('utc', now()),
@ -24,3 +25,4 @@ CREATE INDEX IF NOT EXISTS form_idx ON form_submissions USING btree (form_id);
COMMENT ON table form_submissions IS 'Respondants submit forms/fields to the collector as form_submissions';
COMMENT ON column form_submissions.fields IS 'all form submissions are serialized to JSON, see types.FormFieldValue for structure details';
COMMENT ON column form_submissions.subject_id IS 'identifies the subject/respondent who filled out the form';

View file

@ -17,6 +17,7 @@ func TestCreateShortCode(t *testing.T) {
PostgresDisableSSL: true,
WorkspaceID: "1",
WorkspaceIDUrlParam: "client_id",
PostgresSchema: "frm_test",
})
if err != nil {
t.Error(err)

View file

@ -115,6 +115,8 @@ type FormSubmission struct {
ID int64 `json:"id"`
FormID *int64 `json:"form_id"`
WorkspaceID string `json:"workspace_id"`
// identifies the subject/respondent who filled out the form
SubjectID *string `json:"subject_id"`
// all form submissions are serialized to JSON, see types.FormFieldValue for structure details
Fields types.FormFieldValues `json:"fields"`
Status SubmissionStatus `json:"status"`

View file

@ -397,7 +397,7 @@ VALUES (coalesce(nullif($1, 0), nextval('submission_ids'))::bigint, $2, $3, $4,
UPDATE
SET updated_at = timezone('utc', now()),
fields = $4,
status = $5 RETURNING id, form_id, workspace_id, fields, status, created_at, updated_at
status = $5 RETURNING id, form_id, workspace_id, subject_id, fields, status, created_at, updated_at
`
type SaveSubmissionParams struct {
@ -415,7 +415,7 @@ type SaveSubmissionParams struct {
// UPDATE
// SET updated_at = timezone('utc', now()),
// fields = $4,
// status = $5 RETURNING id, form_id, workspace_id, fields, status, created_at, updated_at
// status = $5 RETURNING id, form_id, workspace_id, subject_id, fields, status, created_at, updated_at
func (q *Queries) SaveSubmission(ctx context.Context, arg SaveSubmissionParams) (FormSubmission, error) {
row := q.db.QueryRow(ctx, saveSubmission,
arg.ID,
@ -429,6 +429,7 @@ func (q *Queries) SaveSubmission(ctx context.Context, arg SaveSubmissionParams)
&i.ID,
&i.FormID,
&i.WorkspaceID,
&i.SubjectID,
&i.Fields,
&i.Status,
&i.CreatedAt,

View file

@ -2603,6 +2603,10 @@ input.tab:checked + .tab-content,
place-self: center;
}
.overflow-visible {
overflow: visible;
}
.overflow-y-auto {
overflow-y: auto;
}
@ -2621,10 +2625,6 @@ input.tab:checked + .tab-content,
border-radius: 0.25rem;
}
.rounded-full {
border-radius: 9999px;
}
.rounded-lg {
border-radius: 0.5rem;
}
@ -2822,6 +2822,11 @@ input.tab:checked + .tab-content,
line-height: 1.25rem;
}
.text-xl {
font-size: 1.25rem;
line-height: 1.75rem;
}
.text-xs {
font-size: 0.75rem;
line-height: 1rem;
@ -2882,6 +2887,11 @@ input.tab:checked + .tab-content,
color: rgb(255 119 119 / var(--tw-text-opacity));
}
.text-slate-700 {
--tw-text-opacity: 1;
color: rgb(51 65 85 / var(--tw-text-opacity));
}
.text-white {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
@ -2954,6 +2964,10 @@ input {
color: rgb(69 69 69 / var(--tw-text-opacity));
}
.focus\:border-2:focus {
border-width: 2px;
}
.focus\:border-transparent:focus {
border-color: transparent;
}

View file

@ -317,7 +317,7 @@ templ builderColumnLeft(form frm.Form) {
// FormPreview previews a frm.Form
templ FormPreview(form frm.Form) {
<section id="builder-main-middle-col" class="w-full h-screen overflow-y-auto overscroll-auto p-4 bg-gray-50 border-y-1">
<div class="mockup-browser border-base-300 border">
<div class="mockup-browser border-base-300 border overflow-visible">
<div class="mockup-browser-toolbar">
<div class="input border-base-300 border">https://your-form-domain.com/form</div>
</div>
@ -803,7 +803,7 @@ templ formFieldTypeLabel(fieldType types.FormFieldType) {
}
templ fieldLabel(field types.FormField) {
<label for={ field.ID.String() }>
<label for={ field.ID.String() } class="text-slate-700 text-xl py-1">
{ field.Label }
if field.Required {
@requiredFieldIndicator()
@ -825,19 +825,20 @@ func (v ViewerMetadata) JSON() string {
return string(b)
}
// FormView renders forms
// FormView is a view of Forms
templ FormView(form frm.Form, isPreview bool) {
<div id="form-viewer" class="flex flex-col w-1/2 mx-auto justify-top pt-12" data-hx-swap-oob="true">
<div
id="form-metadata"
data-data={ ViewerMetadata{Form: form}.JSON() }
></div>
<h1 class="rounded relative mb-2 font-black text-5xl">
<h1 class="rounded relative mb-2 font-black text-slate-700 text-5xl">
{ form.Name }
</h1>
<form
_="on field_change(field_id, value) formValueChanged(field_id, value)"
>
<input name="subject_id" type="hidden"/>
for _, field := range sortFields(form.Fields) {
<div
id={ fmt.Sprintf("field-container-%s", field.ID.String()) }
@ -861,7 +862,7 @@ templ FormView(form frm.Form, isPreview bool) {
type="text"
autocomplete="off"
_={ fmt.Sprintf("on keyup debounced at 250ms trigger field_change(field_id: '%s', value: my.value)", field.ID.String()) }
class="border-gray-300 dark:border-gray-600 rounded-full bg-sky-50"
class="flex-1 appearance-none border border-gray-300 dark:border-gray-600 w-full text-gray-700 dark:bg-notion-dark-light dark:text-gray-300 dark:placeholder-gray-500 placeholder-gray-400 shadow-sm focus:outline-none focus:ring-2 focus:border-2 focus:ring-opacity-100 px-4 py-2 text-base resize-y block rounded-xl bg-sky-50"
/>
case types.FormFieldTypeTextMultiple:
@fieldLabel(field)
@ -871,7 +872,6 @@ templ FormView(form frm.Form, isPreview bool) {
class="flex-1 appearance-none border border-gray-300 dark:border-gray-600 w-full text-gray-700 dark:bg-notion-dark-light dark:text-gray-300 dark:placeholder-gray-500 placeholder-gray-400 shadow-sm focus:outline-none focus:ring-2 focus:border-transparent focus:ring-opacity-100 px-4 py-2 text-base resize-y block rounded-xl bg-sky-50"
placeholder={ field.Placeholder }
autocomplete="off"
style="--tw-ring-color: #3B82F6;"
_={ fmt.Sprintf("on keyup debounced at 250ms trigger field_change(field_id: '%s', value: my.value)", field.ID.String()) }
rows="3"
></textarea>
@ -880,6 +880,7 @@ templ FormView(form frm.Form, isPreview bool) {
ID: field.ID.String(),
Name: field.ID.String(),
Label: field.Label,
LabelClass: "text-slate-700 text-xl py-1",
Required: field.Required,
Placeholder: field.Placeholder,
Multiple: field.Type == types.FormFieldTypeMultiSelect,

View file

@ -2505,7 +2505,7 @@ func (v ViewerMetadata) JSON() string {
return string(b)
}
// FormView renders forms
// FormView is a view of Forms
func FormView(form frm.Form, isPreview bool) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -2565,7 +2565,7 @@ func FormView(form frm.Form, isPreview bool) templ.Component {
var templ_7745c5c3_Var112 string
templ_7745c5c3_Var112, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("field-container-%s", field.ID.String()))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 843, Col: 62}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 844, Col: 62}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var112))
if templ_7745c5c3_Err != nil {
@ -2593,7 +2593,7 @@ func FormView(form frm.Form, isPreview bool) templ.Component {
var templ_7745c5c3_Var113 string
templ_7745c5c3_Var113, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("errors-%s", field.ID.String()))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 851, Col: 54}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 852, Col: 54}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var113))
if templ_7745c5c3_Err != nil {
@ -2616,7 +2616,7 @@ func FormView(form frm.Form, isPreview bool) templ.Component {
var templ_7745c5c3_Var114 string
templ_7745c5c3_Var114, templ_7745c5c3_Err = templ.JoinStringErrs(field.ID.String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 858, Col: 30}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 859, Col: 30}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var114))
if templ_7745c5c3_Err != nil {
@ -2629,7 +2629,7 @@ func FormView(form frm.Form, isPreview bool) templ.Component {
var templ_7745c5c3_Var115 string
templ_7745c5c3_Var115, templ_7745c5c3_Err = templ.JoinStringErrs(field.ID.String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 859, Col: 32}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 860, Col: 32}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var115))
if templ_7745c5c3_Err != nil {
@ -2642,7 +2642,7 @@ func FormView(form frm.Form, isPreview bool) templ.Component {
var templ_7745c5c3_Var116 string
templ_7745c5c3_Var116, templ_7745c5c3_Err = templ.JoinStringErrs(field.Placeholder)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 860, Col: 39}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 861, Col: 39}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var116))
if templ_7745c5c3_Err != nil {
@ -2655,7 +2655,7 @@ func FormView(form frm.Form, isPreview bool) templ.Component {
var templ_7745c5c3_Var117 string
templ_7745c5c3_Var117, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("on keyup debounced at 250ms trigger field_change(field_id: '%s', value: my.value)", field.ID.String()))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 863, Col: 127}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 864, Col: 127}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var117))
if templ_7745c5c3_Err != nil {
@ -2677,7 +2677,7 @@ func FormView(form frm.Form, isPreview bool) templ.Component {
var templ_7745c5c3_Var118 string
templ_7745c5c3_Var118, templ_7745c5c3_Err = templ.JoinStringErrs(field.ID.String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 869, Col: 30}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 870, Col: 30}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var118))
if templ_7745c5c3_Err != nil {
@ -2690,7 +2690,7 @@ func FormView(form frm.Form, isPreview bool) templ.Component {
var templ_7745c5c3_Var119 string
templ_7745c5c3_Var119, templ_7745c5c3_Err = templ.JoinStringErrs(field.ID.String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 870, Col: 32}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 871, Col: 32}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var119))
if templ_7745c5c3_Err != nil {
@ -2703,7 +2703,7 @@ func FormView(form frm.Form, isPreview bool) templ.Component {
var templ_7745c5c3_Var120 string
templ_7745c5c3_Var120, templ_7745c5c3_Err = templ.JoinStringErrs(field.Placeholder)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 872, Col: 39}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 873, Col: 39}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var120))
if templ_7745c5c3_Err != nil {
@ -2731,6 +2731,7 @@ func FormView(form frm.Form, isPreview bool) templ.Component {
ID: field.ID.String(),
Name: field.ID.String(),
Label: field.Label,
LabelClass: "text-slate-700 text-xl py-1",
Required: field.Required,
Placeholder: field.Placeholder,
Multiple: field.Type == types.FormFieldTypeMultiSelect,

View file

@ -51,7 +51,7 @@
\"></form></div>
<section id=\"builder-main-left-col\" class=\"flex flex-col gap-3 w-1/4 min-w-max h-full p-4 text-gray-800 rounded-md\">
</section>
<section id=\"builder-main-middle-col\" class=\"w-full h-screen overflow-y-auto overscroll-auto p-4 bg-gray-50 border-y-1\"><div class=\"mockup-browser border-base-300 border\"><div class=\"mockup-browser-toolbar\"><div class=\"input border-base-300 border\">https://your-form-domain.com/form</div></div><div class=\"flex h-full border-base-300 bg-sky-100 border-t px-4 py-8\">
<section id=\"builder-main-middle-col\" class=\"w-full h-screen overflow-y-auto overscroll-auto p-4 bg-gray-50 border-y-1\"><div class=\"mockup-browser border-base-300 border overflow-visible\"><div class=\"mockup-browser-toolbar\"><div class=\"input border-base-300 border\">https://your-form-domain.com/form</div></div><div class=\"flex h-full border-base-300 bg-sky-100 border-t px-4 py-8\">
</div></div></section>
<div class=\"p-1 rounded-md flex items-center justify-center bg-blue-100 text-blue-900 ml-2\">
</div>
@ -154,12 +154,12 @@ Multi select
<label class=\"w-full cursor-pointer truncate\">I unno</label>
</label></div>
<label for=\"
\">
\" class=\"text-slate-700 text-xl py-1\">
</label>
<div id=\"form-viewer\" class=\"flex flex-col w-1/2 mx-auto justify-top pt-12\" data-hx-swap-oob=\"true\"><div id=\"form-metadata\" data-data=\"
\"></div><h1 class=\"rounded relative mb-2 font-black text-5xl\">
</h1><form _=\"on field_change(field_id, value) formValueChanged(field_id, value)\">
\"></div><h1 class=\"rounded relative mb-2 font-black text-slate-700 text-5xl\">
</h1><form _=\"on field_change(field_id, value) formValueChanged(field_id, value)\"><input name=\"subject_id\" type=\"hidden\">
<div id=\"
\"
class=\"flex flex-col py-3 hidden\"
@ -170,11 +170,11 @@ Multi select
\" name=\"
\" placeholder=\"
\" type=\"text\" autocomplete=\"off\" _=\"
\" class=\"border-gray-300 dark:border-gray-600 rounded-full bg-sky-50\">
\" class=\"flex-1 appearance-none border border-gray-300 dark:border-gray-600 w-full text-gray-700 dark:bg-notion-dark-light dark:text-gray-300 dark:placeholder-gray-500 placeholder-gray-400 shadow-sm focus:outline-none focus:ring-2 focus:border-2 focus:ring-opacity-100 px-4 py-2 text-base resize-y block rounded-xl bg-sky-50\">
<textarea id=\"
\" name=\"
\" class=\"flex-1 appearance-none border border-gray-300 dark:border-gray-600 w-full text-gray-700 dark:bg-notion-dark-light dark:text-gray-300 dark:placeholder-gray-500 placeholder-gray-400 shadow-sm focus:outline-none focus:ring-2 focus:border-transparent focus:ring-opacity-100 px-4 py-2 text-base resize-y block rounded-xl bg-sky-50\" placeholder=\"
\" autocomplete=\"off\" style=\"--tw-ring-color: #3B82F6;\" _=\"
\" autocomplete=\"off\" _=\"
\" rows=\"3\"></textarea>
</div>
<div class=\"py-3\"></div>

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB