Files
myprojplanet_vite/src/components/CDateTimeStartEnd/CDateTimeStartEnd.ts
Surya Paolo df98ec9471 - corretto problema ROGNOSO : Risolvere la questione "Sessioni multiple", se apro 2 browser l'ultimo va a cancellare il precedente, e mi da errore di email non valida !
Il problema era sulla fetch nel service worker, gestita in quel modo personalizzato, andava in conflitto, non tenendo le chiamate bloccanti, ma uscivano prima che arrivasse la risposta del server.
- Per chi è da tanto che non si collega a RISO, compare "Email non verificata"... (si risolve chiudendo su ESCI e riloggandosi)... però andrebbe sistemata.
(stesso problema di prima).
2025-10-26 02:47:59 +02:00

364 lines
11 KiB
TypeScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { defineComponent, ref, watch, computed } from 'vue';
import { useQuasar } from 'quasar';
import { useI18n } from 'vue-i18n';
import { tools } from '@src/store/Modules/tools';
import { toolsext } from '@store/Modules/toolsext';
function toTS(s: string | null): number | null {
if (!s) return null;
const iso = s.includes('T') ? s : s.replace(' ', 'T');
const ts = Date.parse(iso);
return Number.isNaN(ts) ? null : ts;
}
export default defineComponent({
name: 'CDateTimeStartEnd',
emits: [
'update:startValue',
'update:endValue',
'show',
'savetoclose',
'clear-start',
'clear-end',
],
props: {
startValue: { type: [String, Date, null] as unknown as () => string | null, default: null },
endValue: { type: [String, Date, null] as unknown as () => string | null, default: null },
startLabel: { type: String, default: 'Inizio' },
endLabel: { type: String, default: 'Fine' },
data_class: { type: String, default: '' },
canEdit: { type: Boolean, default: true },
disable: { type: Boolean, default: false },
bgcolor: { type: String, default: '' },
dense: { type: Boolean, default: false },
view: { type: String as () => 'date-time' | 'date' | 'time', default: 'date-time' },
nullableStart: { type: Boolean, default: true },
nullableEnd: { type: Boolean, default: true },
nullText: { type: String, default: '—' },
calendarIcon: { type: String, default: 'fas fa-calendar-day' },
clockIcon: { type: String, default: 'fas fa-clock' },
clearIcon: { type: String, default: 'fas fa-ban' },
optionalText: { type: String, default: 'opzionale' },
enableEndText: { type: String, default: 'Attiva' },
},
setup(props, { emit }) {
const $q = useQuasar();
const { t } = useI18n();
const isMobile = computed(() => $q.screen.lt.sm);
// local state
const startVal = ref<string | null>(null);
const endVal = ref<string | null>(null);
const startPrev = ref<string | null>(null);
const endPrev = ref<string | null>(null);
// dialog states
const startDateDialog = ref(false);
const startTimeDialog = ref(false);
const endDateDialog = ref(false);
const endTimeDialog = ref(false);
const startDateDesktopDialog = ref(false);
const startTimeDesktopDialog = ref(false);
const endDateDesktopDialog = ref(false);
const endTimeDesktopDialog = ref(false);
const endError = ref<string>('');
// sync props -> local
watch(
() => props.startValue,
(v) => {
startVal.value = v ? tools.getstrYYMMDDDateTime(v) : null;
},
{ immediate: true }
);
watch(
() => props.endValue,
(v) => {
endVal.value = v ? tools.getstrYYMMDDDateTime(v) : null;
validateRange();
},
{ immediate: true }
);
function getstrDate(val: string | Date | null) {
if (!val) return props.nullText;
if (props.view === 'date-time') return tools.getstrDateTime(val);
if (props.view === 'date') return tools.getstrDate(val);
return tools.getstrTime(val);
}
function opening(kind: 'start' | 'end') {
if (kind === 'start') {
startPrev.value = startVal.value;
if (!startVal.value) startVal.value = tools.getstrYYMMDDDateTime(new Date());
} else {
endPrev.value = endVal.value;
if (!endVal.value)
endVal.value = startVal.value || tools.getstrYYMMDDDateTime(new Date());
}
endError.value = '';
emit('show');
}
function cancelStart() {
startVal.value = startPrev.value;
closeAllStart();
}
function cancelEnd() {
endVal.value = endPrev.value;
endError.value = '';
closeAllEnd();
}
function saveStart() {
const currStart = startVal.value;
const prevStart = startPrev.value;
// salva start
emit('update:startValue', currStart as unknown as string);
emit('savetoclose', { which: 'start', current: currStart, prev: prevStart });
// Se esiste end e l'intervallo è invalido, riallinea fine preservando l'ora originale
if (endVal.value) {
const tsStart = toTS(currStart);
const tsEnd = toTS(endVal.value);
if (tsStart !== null && tsEnd !== null && tsEnd < tsStart) {
endVal.value = buildEndWithStartDatePreservingEndTime(tsStart, tsEnd);
endError.value = '';
emit('update:endValue', endVal.value as unknown as string);
emit('savetoclose', { which: 'end', current: endVal.value, prev: endPrev.value });
tools.showNeutralNotif(
$q,
t('date.rangeFixed') || 'Fine allineata allinizio mantenendo lora originale'
);
}
}
closeAllStart();
}
/**
* Costruisce una nuova data di fine usando:
* - data (Y/M/D) = quella di start
* - ora (h:m:s:ms) = quella di end originale
* Se il risultato è ancora < start, sposta end al giorno successivo mantenendo la stessa ora.
*/
function buildEndWithStartDatePreservingEndTime(
tsStart: number,
tsEnd: number
): string {
// Se il componente è solo 'date', non c'è ora da preservare: end = start
if (props.view === 'date') {
return tools.getstrYYMMDDDateTime(new Date(tsStart));
}
const dStart = new Date(tsStart);
const dEnd = new Date(tsEnd);
// Ricostruisci end: data = start, ora = end originale
const newEnd = new Date(
dStart.getFullYear(),
dStart.getMonth(),
dStart.getDate(),
dEnd.getHours(),
dEnd.getMinutes(),
dEnd.getSeconds(),
dEnd.getMilliseconds()
);
// Se così è ancora < start (es. end 08:00, start 10:00 stesso giorno) → bump di 1 giorno
if (newEnd.getTime() < tsStart) {
newEnd.setDate(newEnd.getDate() + 1);
}
return tools.getstrYYMMDDDateTime(newEnd);
}
function saveEnd() {
if (!validateRange(true)) {
// blocco il salvataggio se ancora invalida
return;
}
emit('update:endValue', endVal.value as unknown as string);
emit('savetoclose', { which: 'end', current: endVal.value, prev: endPrev.value });
closeAllEnd();
}
function onStartChange(v: string | Date) {
startVal.value = typeof v === 'string' ? v : tools.getstrYYMMDDDateTime(v);
}
function onEndChange(v: string | Date) {
endVal.value = typeof v === 'string' ? v : tools.getstrYYMMDDDateTime(v);
validateRange();
}
function clearStart() {
startVal.value = null;
emit('update:startValue', null as unknown as string);
emit('savetoclose', { which: 'start', current: null, prev: startPrev.value });
// se non c'è inizio, rimuovo anche fine per coerenza
if (endVal.value) {
endVal.value = null;
emit('update:endValue', null as unknown as string);
emit('savetoclose', { which: 'end', current: null, prev: endPrev.value });
}
emit('clear-start');
tools.showNeutralNotif($q, t('common.cleared') || 'Valore rimosso');
closeAllStart();
}
function clearEnd() {
endVal.value = null;
emit('update:endValue', null as unknown as string);
emit('clear-end');
tools.showNeutralNotif($q, t('common.cleared') || 'Valore rimosso');
endError.value = '';
closeAllEnd();
}
function enableEnd() {
endVal.value = startVal.value || tools.getstrYYMMDDDateTime(new Date());
validateRange(true);
emit('update:endValue', endVal.value as unknown as string);
}
function openStartDate() {
opening('start');
if (isMobile.value) startDateDialog.value = true;
else startDateDesktopDialog.value = true;
}
function openStartTime() {
opening('start');
if (isMobile.value) startTimeDialog.value = true;
else startTimeDesktopDialog.value = true;
}
function openEndDate() {
opening('end');
if (isMobile.value) endDateDialog.value = true;
else endDateDesktopDialog.value = true;
}
function openEndTime() {
opening('end');
if (isMobile.value) endTimeDialog.value = true;
else endTimeDesktopDialog.value = true;
}
function closeAllStart() {
startDateDialog.value = false;
startTimeDialog.value = false;
startDateDesktopDialog.value = false;
startTimeDesktopDialog.value = false;
}
function closeAllEnd() {
endDateDialog.value = false;
endTimeDialog.value = false;
endDateDesktopDialog.value = false;
endTimeDesktopDialog.value = false;
}
function validateRange(showMsg = false): boolean {
endError.value = '';
const tsStart = toTS(startVal.value);
const tsEnd = toTS(endVal.value);
if (tsStart != null && tsEnd != null && tsEnd < tsStart) {
endError.value =
t('date.invalidRange') || 'La data di fine non può precedere linizio';
if (showMsg) tools.showNeutralNotif($q, endError.value);
return false;
}
return true;
}
const confirmLabelStartDate = computed(() =>
isMobile.value
? t('common.set') || 'Imposta'
: `Imposta a ${tools.getstrDateLong(startVal.value)}`
);
const confirmLabelStartTime = computed(() =>
isMobile.value
? t('common.set') || 'Imposta'
: `Imposta a ${tools.getstrTime(startVal.value)}`
);
const confirmLabelEndDate = computed(() =>
isMobile.value
? t('common.set') || 'Imposta'
: `Imposta a ${tools.getstrDateLong(endVal.value)}`
);
const confirmLabelEndTime = computed(() =>
isMobile.value
? t('common.set') || 'Imposta'
: `Imposta a ${tools.getstrTime(endVal.value)}`
);
const canEditEnd = computed(() => !!endVal.value || !props.nullableEnd);
return {
toolsext,
tools,
// values & labels
startVal,
endVal,
startLabel: computed(() => props.startLabel),
endLabel: computed(() => props.endLabel),
// ui flags
dense: props.dense,
bgcolor: props.bgcolor,
disable: props.disable,
data_class: props.data_class,
canEdit: props.canEdit,
nullableStart: props.nullableStart,
nullableEnd: props.nullableEnd,
nullText: props.nullText,
optionalText: props.optionalText,
enableEndText: props.enableEndText,
calendarIcon: props.calendarIcon,
clockIcon: props.clockIcon,
clearIcon: props.clearIcon,
// dialogs
startDateDialog,
startTimeDialog,
endDateDialog,
endTimeDialog,
startDateDesktopDialog,
startTimeDesktopDialog,
endDateDesktopDialog,
endTimeDesktopDialog,
// methods
getstrDate,
openStartDate,
openStartTime,
openEndDate,
openEndTime,
cancelStart,
cancelEnd,
saveStart,
saveEnd,
onStartChange,
onEndChange,
clearStart,
clearEnd,
enableEnd,
// helpers
confirmLabelStartDate,
confirmLabelStartTime,
confirmLabelEndDate,
confirmLabelEndTime,
isMobile,
canEditEnd,
endError,
};
},
});