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

Fix/Date form #30

Merged
merged 16 commits into from
Sep 17, 2023
142 changes: 64 additions & 78 deletions forms/DateForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,24 @@
<h3>{{ $t('date-form.input-title') }}</h3>
<div class="date-form__input-fields">
<input-field
v-for="(_, name) in form"
:key="name"
v-model="form[name]"
:label="$t(`date-form.${name}-label`)"
:placeholder="$t(`date-form.${name}-placeholder`)"
:error-message="getFieldErrorMessage(name)"
@blur="touchField(name)"
v-for="(_, key) in form"
:key="key"
v-model="form[key]"
type="number"
:label="$t(`date-form.${key}-label`)"
:placeholder="$t(`date-form.${key}-placeholder`)"
:error-message="getFieldErrorMessage(key)"
@blur="touchField(key)"
/>
</div>
<datetime-field
:model-value="calendarDate"
@update:model-value="setDate($event)"
:model-value="datetimeFieldTimestamp"
@update:model-value="setForm(new Time($event))"
/>
</div>
<div class="date-form__output">
<h3>{{ $t('date-form.output-title') }}</h3>
<div v-for="(item, idx) in outputItems" :key="`${item.label}-${idx}`">
<div v-for="(item, idx) in outputItems" :key="idx">
<p class="date-form__output-item-label">
{{ item.label }}
</p>
Expand All @@ -38,39 +39,47 @@
import { AppCopy } from '#components'
import { useFormValidation } from '@/composables'
import { DatetimeField, InputField } from '@/fields'
import { ErrorHandler, integer, maxValue, minValue, required } from '@/helpers'
import { integer, maxValue, minValue, required } from '@/helpers'
import { Time } from '@distributedlab/tools'
import { computed, onMounted, reactive, ref, watch } from 'vue'
import { computed, reactive } from 'vue'
import { i18n } from '~/plugins/localization'

const { t } = i18n.global
const calendarDate = ref(new Time().timestamp)
const maxDayInMonth = ref(31)
const currentDate = ref<Date | null>(null)

const form = reactive({
year: '',
month: '',
date: '',
day: '',
hour: '',
minute: '',
second: '',
})

const maxDayInMonth = computed<number>(() => {
const year = Number(form.year)
const month = Number(form.month) - 1

if (!year && !month) return 31
return new Time(new Date(year, month)).dayjs.daysInMonth()
})

const rules = computed(() => ({
year: {
required,
integer,
minValue: minValue(1970),
minValue: minValue(1924),
maxValue: maxValue(10000),
},
month: {
required,
integer,
minValue: minValue(1),
minValue: {
/** Date object with month of 1924 before May works incorrectly */
...(form.year === '1924' ? minValue(5) : minValue(1)),
},
maxValue: maxValue(12),
},
date: {
day: {
required,
integer,
minValue: minValue(1),
Expand All @@ -91,74 +100,51 @@ const rules = computed(() => ({
},
}))

const { isFormValid, getFieldErrorMessage, touchField, isFieldsValid } =
useFormValidation(form, rules)
const { getFieldErrorMessage, isFormValid, touchField } = useFormValidation(
form,
rules,
)

const setForm = (time: Time) => {
form.year = String(time.get('year'))
form.month = String(time.get('month') + 1)
form.day = String(time.get('date'))
form.hour = String(time.get('hour'))
form.minute = String(time.get('minute'))
form.second = String(time.get('second'))
}

setForm(new Time().utc())

const localTime = computed<Time | null>(() => {
if (!isFormValid()) return null

const date = new Date(
Number(form.year),
Number(form.month) - 1,
Number(form.day),
Number(form.hour),
Number(form.minute),
Number(form.second),
)

return new Time(date)
})

const datetimeFieldTimestamp = computed<number>(
() => localTime.value?.timestamp || new Time().timestamp,
)

const outputItems = computed(() => [
{
label: t('date-form.seconds-label'),
value:
isFieldsValid.value && currentDate.value
? new Time(currentDate.value).timestamp.toString()
: '',
value: localTime.value?.utc(true).timestamp.toString() || '',
},
{
label: t('date-form.milliseconds-label'),
value:
isFieldsValid.value && currentDate.value
? new Time(currentDate.value).ms.toString()
: '',
value: localTime.value?.utc(true).ms.toString() || '',
},
])

watch(form, () => {
setMaxDays()

if (!isFormValid()) {
currentDate.value = null
calendarDate.value = new Time().timestamp
return
}

try {
currentDate.value = new Date(
+form.year,
+form.month - 1,
+form.date,
+form.hour,
+form.minute,
+form.second,
)
calendarDate.value = currentDate.value.getTime() / 1000
} catch (error) {
currentDate.value = null
calendarDate.value = new Time().timestamp
ErrorHandler.processWithoutFeedback(error)
}
})

const setDate = (date: Date | number | string) => {
const time = new Time(date)
form.year = time.dayjs.year().toString()
form.month = (time.dayjs.month() + 1).toString()
form.date = time.dayjs.date().toString()
form.hour = time.dayjs.hour().toString()
form.minute = time.dayjs.minute().toString()
form.second = time.dayjs.second().toString()
}

const setMaxDays = () => {
if (getFieldErrorMessage('year') || getFieldErrorMessage('month')) return
maxDayInMonth.value = new Time(
new Date(+form.year, +form.month - 1),
).dayjs.daysInMonth()
}

onMounted(() => {
const time = new Time()
currentDate.value = time.toDate()
setDate(currentDate.value)
})
</script>

<style lang="scss" scoped>
Expand Down
4 changes: 2 additions & 2 deletions plugins/localization/resources/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,13 @@
"input-title": "Enter Date and Time",
"year-label": "Year",
"month-label": "Month",
"date-label": "Day",
"day-label": "Day",
"hour-label": "Hour",
"minute-label": "Minute",
"second-label": "Second",
"year-placeholder": "Year",
"month-placeholder": "Month",
"date-placeholder": "Day",
"day-placeholder": "Day",
"hour-placeholder": "Hour",
"minute-placeholder": "Minute",
"second-placeholder": "Second",
Expand Down