feat(notes): let organizations define their own note fields
The note form was fixed. Owners can add fields and each note keeps those values. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
<script setup lang="ts">
|
||||
import type { CustomFieldDefinitionDto } from '@mento/shared';
|
||||
import JalaliDateInput from '@/components/JalaliDateInput.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
fields: CustomFieldDefinitionDto[];
|
||||
modelValue: Record<string, unknown>;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: Record<string, unknown>];
|
||||
}>();
|
||||
|
||||
function setValue(key: string, value: unknown) {
|
||||
emit('update:modelValue', { ...props.modelValue, [key]: value });
|
||||
}
|
||||
|
||||
function textValue(key: string) {
|
||||
const value = props.modelValue[key];
|
||||
if (value == null) return '';
|
||||
return String(value);
|
||||
}
|
||||
|
||||
function numberValue(key: string) {
|
||||
const value = props.modelValue[key];
|
||||
if (value == null || value === '') return '';
|
||||
const n = Number(value);
|
||||
return Number.isFinite(n) ? String(n) : '';
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="fields.length" class="note-custom-fields">
|
||||
<p class="note-custom-title">فیلدهای اختصاصی</p>
|
||||
<div v-for="field in fields" :key="field.id" class="field">
|
||||
<span>
|
||||
{{ field.label }}
|
||||
<em v-if="field.required">*</em>
|
||||
</span>
|
||||
|
||||
<select
|
||||
v-if="field.fieldType === 'select'"
|
||||
:value="textValue(field.key)"
|
||||
@change="setValue(field.key, ($event.target as HTMLSelectElement).value)"
|
||||
>
|
||||
<option value="">انتخاب کنید</option>
|
||||
<option v-for="opt in field.options" :key="opt" :value="opt">{{ opt }}</option>
|
||||
</select>
|
||||
|
||||
<label v-else-if="field.fieldType === 'boolean'" class="check-line">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="props.modelValue[field.key] === true"
|
||||
@change="setValue(field.key, ($event.target as HTMLInputElement).checked)"
|
||||
/>
|
||||
<span>بله</span>
|
||||
</label>
|
||||
|
||||
<input
|
||||
v-else-if="field.fieldType === 'number'"
|
||||
type="number"
|
||||
:value="numberValue(field.key)"
|
||||
@input="
|
||||
setValue(
|
||||
field.key,
|
||||
($event.target as HTMLInputElement).value === ''
|
||||
? null
|
||||
: Number(($event.target as HTMLInputElement).value),
|
||||
)
|
||||
"
|
||||
/>
|
||||
|
||||
<JalaliDateInput
|
||||
v-else-if="field.fieldType === 'date'"
|
||||
:model-value="textValue(field.key)"
|
||||
@update:model-value="setValue(field.key, $event || null)"
|
||||
/>
|
||||
|
||||
<input
|
||||
v-else
|
||||
type="text"
|
||||
:value="textValue(field.key)"
|
||||
@input="setValue(field.key, ($event.target as HTMLInputElement).value)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.note-custom-fields {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.55rem;
|
||||
}
|
||||
.note-custom-title {
|
||||
margin: 0.2rem 0 0;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 700;
|
||||
color: #0f766e;
|
||||
}
|
||||
.field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3rem;
|
||||
font-size: 0.82rem;
|
||||
color: #64748b;
|
||||
}
|
||||
.field em {
|
||||
color: #b91c1c;
|
||||
font-style: normal;
|
||||
}
|
||||
.field select,
|
||||
.field input[type='text'],
|
||||
.field input[type='number'] {
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 10px;
|
||||
padding: 0.45rem 0.55rem;
|
||||
font-size: 0.9rem;
|
||||
color: #0f172a;
|
||||
background: #fff;
|
||||
}
|
||||
.check-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
color: #0f172a;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user