Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dc3e4 new matrix field #484

Merged
merged 36 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
a4ac0d1
fix password reset bug
madassdev May 27, 2024
9345436
Merge branch 'main' of https://github.com/JhumanJ/OpnForm
madassdev May 28, 2024
c4e069f
Merge branch 'main' of https://github.com/JhumanJ/OpnForm
madassdev May 28, 2024
ad07808
Merge branch 'main' of https://github.com/JhumanJ/OpnForm
madassdev May 30, 2024
ce99260
Merge branch 'main' of https://github.com/JhumanJ/OpnForm
madassdev Jun 3, 2024
840e9c1
Merge branch 'main' of https://github.com/JhumanJ/OpnForm
madassdev Jun 5, 2024
d443551
Merge branch 'main' of https://github.com/JhumanJ/OpnForm
madassdev Jun 7, 2024
267e631
Merge branch 'main' of https://github.com/JhumanJ/OpnForm
madassdev Jun 10, 2024
34ff509
Merge branch 'main' of https://github.com/JhumanJ/OpnForm
madassdev Jun 10, 2024
8697ede
Merge branch 'main' of https://github.com/JhumanJ/OpnForm
madassdev Jun 11, 2024
9bf816c
Merge branch 'main' of https://github.com/JhumanJ/OpnForm
madassdev Jun 18, 2024
bdc64bc
Merge branch 'main' of https://github.com/JhumanJ/OpnForm
madassdev Jun 19, 2024
4a5b72c
Merge branch 'main' of https://github.com/JhumanJ/OpnForm
madassdev Jun 25, 2024
49a8a04
Merge branch 'main' of https://github.com/JhumanJ/OpnForm
madassdev Jul 1, 2024
7079bd4
Merge branch 'main' of https://github.com/JhumanJ/OpnForm
madassdev Jul 3, 2024
a9c5371
wip: matrix input
madassdev Jul 11, 2024
d633500
wip: matrix input
madassdev Jul 18, 2024
88c3a67
wip: matrix input
madassdev Jul 19, 2024
0c37a89
Fixed matric input component logic
JhumanJ Jul 19, 2024
a853c82
matrix input cleanup
madassdev Jul 23, 2024
a307379
fix lint errors
madassdev Jul 23, 2024
4e87cf8
Merge branch 'dc3e4-new-matrix-field' of https://github.com/JhumanJ/O…
madassdev Jul 23, 2024
ca723b6
table border and radius
madassdev Jul 23, 2024
046038b
cleanup, linting
madassdev Jul 23, 2024
82fe4b0
Merge remote-tracking branch 'origin/main' into dc3e4-new-matrix-field
madassdev Jul 23, 2024
a1dbd4a
fix component methos
madassdev Jul 23, 2024
c1cfcac
wip matrix input
madassdev Jul 30, 2024
c7f7e5d
matrix condition for contains and not contain
madassdev Aug 1, 2024
e19c461
patch matrix input condition logic
madassdev Aug 6, 2024
54b7a7b
linting
madassdev Aug 6, 2024
104eabe
refactor and cleanup
madassdev Aug 6, 2024
4d4b747
fix syntax error
madassdev Aug 13, 2024
1b6ec44
Merge remote-tracking branch 'origin/main' into dc3e4-new-matrix-field
madassdev Aug 13, 2024
88ec9a3
Merge branch 'main' into dc3e4-new-matrix-field
JhumanJ Aug 23, 2024
8afbdb1
Polished the matrix input
JhumanJ Aug 23, 2024
24ac419
Fix linting
JhumanJ Aug 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion app/Http/Requests/AnswerFormRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use App\Models\Forms\Form;
use App\Rules\CustomFieldValidationRule;
use App\Rules\MatrixValidationRule;
use App\Rules\StorageFile;
use App\Rules\ValidHCaptcha;
use App\Rules\ValidPhoneInputRule;
Expand Down Expand Up @@ -82,6 +83,8 @@ public function rules()
} elseif ($property['type'] == 'rating') {
// For star rating, needs a minimum of 1 star
$rules[] = 'min:1';
} elseif ($property['type'] == 'matrix') {
$rules[] = new MatrixValidationRule();
}
} else {
$rules[] = 'nullable';
Expand All @@ -97,7 +100,7 @@ public function rules()
}

// User custom validation
if(!(Str::of($property['type'])->startsWith('nf-')) && isset($property['validation'])) {
if (!(Str::of($property['type'])->startsWith('nf-')) && isset($property['validation'])) {
$rules[] = (new CustomFieldValidationRule($property['validation'], $data));
}

Expand Down
28 changes: 28 additions & 0 deletions app/Rules/MatrixValidationRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class MatrixValidationRule implements ValidationRule
{
/**
* Run the validation rule.
*
* @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (!is_array($value)) {
$fail('The Matrix field must be an array.');
return;
}
$nullValues = array_filter($value, function ($val) {
return $val === null;
});
if (sizeof($nullValues)) {
$fail('The Matrix field is required.');
}
}
}
15 changes: 15 additions & 0 deletions app/Service/Forms/FormSubmissionFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,17 @@ public function useSignedUrlForFiles()
return $this;
}

public function getMatrixString(array $val): string
{
$parts = [];
foreach ($val as $key => $value) {
if ($key !== null && $value !== null) {
$parts[] = "$key: $value";
}
}
return implode(' | ', $parts);
}

/**
* Return a nice "FieldName": "Field Response" array
* - If createLink enabled, returns html link for emails and links
Expand Down Expand Up @@ -145,6 +156,8 @@ public function getCleanKeyValue()
} else {
$returnArray[$field['name']] = $val;
}
} elseif ($field['type'] == 'matrix') {
$returnArray[$field['name']] = $this->getMatrixString($data[$field['id']]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validate matrix data type.

Ensure that the matrix data is always an array before passing it to getMatrixString.

} elseif ($field['type'] == 'matrix' && is_array($data[$field['id']])) {
    $returnArray[$field['name']] = $this->getMatrixString($data[$field['id']]);
}

} elseif ($field['type'] == 'files') {
if ($this->outputStringsOnly) {
$formId = $this->form->id;
Expand Down Expand Up @@ -219,6 +232,8 @@ public function getFieldsWithValue()
} else {
$field['value'] = $val;
}
} elseif ($field['type'] == 'matrix') {
$field['value'] = str_replace(' | ', "\n", $this->getMatrixString($data[$field['id']]));
} elseif ($field['type'] == 'files') {
if ($this->outputStringsOnly) {
$formId = $this->form->id;
Expand Down
1 change: 0 additions & 1 deletion client/components/forms/FlatSelectInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
theme.default.input,
theme.default.borderRadius,
{
'mb-2': index !== options.length,
'!ring-red-500 !ring-2 !border-transparent': hasError,
'!cursor-not-allowed !bg-gray-200': disabled,
},
Expand Down
117 changes: 117 additions & 0 deletions client/components/forms/MatrixInput.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<template>
<input-wrapper v-bind="inputWrapperProps">
<template #label>
<slot name="label"/>
</template>
<div class='border' :class="[
theme.default.borderRadius,
{
'!ring-red-500 !ring-2 !border-transparent': hasError,
'!cursor-not-allowed !bg-gray-200': disabled,
},
]">
<table
class="w-full table-fixed overflow-hidden border border-collapse border-transparent"
:class="[
theme.default.borderRadius]"
>
<thead class="">
<tr class="bg-gray-200/60">
<th @click="test" class="border border-gray-300">

</th>
<td v-for="column in columns" :key="column" class="border border-gray-300">
<div class="p-2 w-full flex items-center justify-center capitalize text-sm truncate">
{{ column }}
</div>
</td>
</tr>
</thead>

<tbody>
<tr v-for="row, rowIndex in rows" :key="rowIndex" class="">
<td class="border border-gray-300">
<div class="w-full flex-grow p-2 text-sm truncate">
{{ row }}
</div>
</td>
<td v-for="column in columns" :key="row + column" class="border border-gray-300">
<div
class="w-full flex items-center justify-center hover:bg-gray-200/40"
v-if="compVal"
role="radio"
:aria-checked="compVal[row] === column"
:class="[
theme.FlatSelectInput.spacing.vertical,
theme.FlatSelectInput.fontSize,
theme.FlatSelectInput.option,
]"
@click="onSelect(row, column)"
>
<Icon
v-if="compVal[row] === column"
:key="row+column"
name="material-symbols:radio-button-checked-outline"
class="text-inherit"
:color="color"
:class="[theme.FlatSelectInput.icon]"
/>
<Icon
v-else
:key="row+column"
name="material-symbols:radio-button-unchecked"
:class="[theme.FlatSelectInput.icon,theme.FlatSelectInput.unselectedIcon]"
/>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<template #help>
<slot name="help"/>
</template>
<template #error>
<slot name="error"/>
</template>
</input-wrapper>
</template>
<script>
import {inputProps, useFormInput} from "./useFormInput.js"
import InputWrapper from "./components/InputWrapper.vue"

export default {
name: "MatrixInput",
components: {InputWrapper},

props: {
...inputProps,
rows: {type: Array, required: true},
columns: {type: Array, required: true},
},
data() {
return {
}
},
setup(props, context) {
return {
...useFormInput(props, context),
}
},
computed: {},
methods: {
onSelect(row, column) {
if (this.compVal[row] === column) {
this.compVal[row] = null
} else {
this.compVal[row] = column
}
},
},
beforeMount() {
if (!this.compVal || typeof this.compVal !== 'object') {
this.compVal = {}
}
},
}
</script>
42 changes: 42 additions & 0 deletions client/components/forms/components/MatrixRadioInput.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<template>
<div
role="radio"
:aria-checked="selected"
:class="[
theme.FlatSelectInput.spacing.vertical,
theme.FlatSelectInput.fontSize,
theme.FlatSelectInput.option,
]"
@click="onSelect"
>
<Icon
v-if="selected"
name="material-symbols:radio-button-checked-outline"
class="text-inherit"
:color="color"
:class="[theme.FlatSelectInput.icon]"
/>
<Icon
v-else
name="material-symbols:radio-button-unchecked"
:class="[theme.FlatSelectInput.icon,theme.FlatSelectInput.unselectedIcon]"
/>
</div>
</template>
<script>
export default {
emits: ['toggle-select'],
props: {
theme: { type: Object },
color: {type: String, default: "#3B82F6"},
selected: { type: Boolean, default: false }
},
methods: {
onSelect(){
this.$emit("toggle-select")
}
}

}

</script>
2 changes: 2 additions & 0 deletions client/components/forms/useFormInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export function useFormInput(props, context, options = {}) {
if (props.form) {
return _get(props.form, (composableOptions.formPrefixKey || "") + props.name)
}
console.log(content.value)
return content.value
},
set: (val) => {
Expand Down Expand Up @@ -92,6 +93,7 @@ export function useFormInput(props, context, options = {}) {
watch(
() => props.modelValue,
(newValue) => {
console.log(newValue, 'watcher')
if (content.value !== newValue) {
content.value = newValue
}
Expand Down
2 changes: 2 additions & 0 deletions client/components/open/forms/OpenForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,8 @@ export default {
formData[field.id] = urlPrefill.getAll(field.id + '[]')
} else if (field.type === 'date' && field.prefill_today === true) { // For Prefill with 'today'
formData[field.id] = new Date().toISOString()
} else if (field.type === 'matrix') {
formData[field.id] = {...field.prefill}
} else { // Default prefill if any
formData[field.id] = field.prefill
}
Expand Down
14 changes: 11 additions & 3 deletions client/components/open/forms/OpenFormField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,10 @@
>
</div>
</template>
<div class="hidden group-hover/nffield:flex translate-x-full absolute right-0 top-0 h-full w-5 flex-col justify-center pl-1 pt-3">
<div class="flex items-center bg-gray-100 dark:bg-gray-800 border rounded-md h-12 text-gray-500 dark:text-gray-400 dark:border-gray-500 cursor-grab handle">
<div
class="hidden group-hover/nffield:flex translate-x-full absolute right-0 top-0 h-full w-5 flex-col justify-center pl-1 pt-3">
<div
class="flex items-center bg-gray-100 dark:bg-gray-800 border rounded-md h-12 text-gray-500 dark:text-gray-400 dark:border-gray-500 cursor-grab handle">
<Icon
name="clarity:drag-handle-line"
class="h-6 w-6 -ml-1 block shrink-0"
Expand Down Expand Up @@ -194,7 +196,8 @@ export default {
checkbox: 'CheckboxInput',
url: 'TextInput',
email: 'TextInput',
phone_number: 'TextInput'
phone_number: 'TextInput',
matrix: 'MatrixInput'
}[field.type]
},
isPublicFormPage() {
Expand Down Expand Up @@ -293,6 +296,11 @@ export default {
isDark: this.darkMode
}

if (field.type === 'matrix') {
inputProperties.rows = field.rows
inputProperties.columns = field.columns
}

if (['select', 'multi_select'].includes(field.type)) {
inputProperties.options = (_has(field, field.type))
? field[field.type].options.map(option => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,11 @@ export default {
title: "Signature Input",
icon: '<path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125" />',
},
{
name: "matrix",
title: "Matrix Input",
icon: '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 0 1-1.125-1.125M3.375 19.5h7.5c.621 0 1.125-.504 1.125-1.125m-9.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75c0 .621-.504 1.125-1.125 1.125m1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125m0 3.75h-7.5A1.125 1.125 0 0 1 12 18.375m9.75-12.75c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125m19.5 0v1.5c0 .621-.504 1.125-1.125 1.125M2.25 5.625v1.5c0 .621.504 1.125 1.125 1.125m0 0h17.25m-17.25 0h7.5c.621 0 1.125.504 1.125 1.125M3.375 8.25c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125m17.25-3.75h-7.5c-.621 0-1.125.504-1.125 1.125m8.625-1.125c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125M12 10.875v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 10.875c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125M13.125 12h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125M20.625 12c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5M12 14.625v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 14.625c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125m0 1.5v-1.5m0 0c0-.621.504-1.125 1.125-1.125m0 0h7.5"></path>',
},
],
layoutBlocks: [
{
Expand Down
25 changes: 23 additions & 2 deletions client/components/open/forms/fields/components/FieldOptions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@
/>
</div>

<MatrixFieldOptions :field="field" />

<MatrixFieldOptions :field="field" />

<!-- Text Options -->
<div
v-if="field.type === 'text' && displayBasedOnAdvanced"
Expand Down Expand Up @@ -423,6 +427,15 @@
label="Pre-filled value"
:multiple="field.type === 'multi_select'"
/>
<template v-else-if="field.type === 'matrix'">
<MatrixInput
:form="field"
:rows="field.rows"
:columns="field.columns"
name="prefill"
label="Pre-filled value"
/>
</template>
<date-input
v-else-if="field.type === 'date' && field.prefill_today !== true"
name="prefill"
Expand Down Expand Up @@ -594,7 +607,7 @@
:field="field"
/>

<custom-field-validation
<custom-field-validation
class="py-2 px-4 border-b pb-16"
:form="form"
:field="field"
Expand All @@ -608,12 +621,13 @@ import countryCodes from '~/data/country_codes.json'
import CountryFlag from 'vue-country-flag-next'
import FormBlockLogicEditor from '../../components/form-logic-components/FormBlockLogicEditor.vue'
import CustomFieldValidation from '../../components/CustomFieldValidation.vue'
import MatrixFieldOptions from './MatrixFieldOptions.vue'
import { format } from 'date-fns'
import { default as _has } from 'lodash/has'

export default {
name: 'FieldOptions',
components: { CountryFlag, FormBlockLogicEditor, CustomFieldValidation },
components: { CountryFlag, FormBlockLogicEditor, CustomFieldValidation, MatrixFieldOptions },
props: {
field: {
type: Object,
Expand Down Expand Up @@ -868,6 +882,13 @@ export default {
date: {
date_format: this.dateFormatOptions[0].value,
time_format: this.timeFormatOptions[0].value
},
matrix: {
rows:['Row 1'],
columns: [1 ,2 ,3],
selection_data:{
'Row 1': null
}
}
}
if (this.field.type in defaultFieldValues) {
Expand Down
Loading
Loading