Setup Wizard
This commit is contained in:
@@ -38,9 +38,21 @@ const cfg = ref({
|
||||
online_ativo: false,
|
||||
setup_clinica_concluido: false,
|
||||
setup_clinica_concluido_em: null,
|
||||
jornada_igual_todos: true
|
||||
jornada_igual_todos: true,
|
||||
timezone: 'America/Sao_Paulo',
|
||||
is_conveniado: false,
|
||||
})
|
||||
|
||||
const timezones = [
|
||||
{ label: 'Brasília (BRT)', value: 'America/Sao_Paulo' },
|
||||
{ label: 'Manaus (AMT)', value: 'America/Manaus' },
|
||||
{ label: 'Fortaleza (BRT)', value: 'America/Fortaleza' },
|
||||
{ label: 'Belém (BRT)', value: 'America/Belem' },
|
||||
{ label: 'Rio Branco (ACT)', value: 'America/Rio_Branco' },
|
||||
{ label: 'Noronha (FNT)', value: 'America/Noronha' },
|
||||
{ label: 'Lisboa (WET)', value: 'Europe/Lisbon' },
|
||||
]
|
||||
|
||||
// ── Jornada ────────────────────────────────────────────────────
|
||||
const regras = ref([])
|
||||
const workDays = ref({ 1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 0: false })
|
||||
@@ -86,7 +98,8 @@ const diasSemana = [
|
||||
{ label: 'Domingo', short: 'Dom', value: 0 }
|
||||
]
|
||||
|
||||
const selectedDays = computed(() => diasSemana.filter(d => !!workDays.value[d.value]))
|
||||
const selectedDays = computed(() => diasSemana.filter(d => !!workDays.value[d.value]))
|
||||
const selectedWeekdays = computed(() => diasSemana.filter(d => d.value >= 1 && d.value <= 5 && !!workDays.value[d.value]))
|
||||
|
||||
function hhmmToMin (hhmm) {
|
||||
const [h, m] = String(hhmm).split(':').map(Number)
|
||||
@@ -196,7 +209,10 @@ const orphanSlotDays = computed(() => {
|
||||
watch([selectedDays, jornadaStart, jornadaEnd], () => {
|
||||
if (!isValidHHMM(jornadaStart.value) || !isValidHHMM(jornadaEnd.value)) return
|
||||
if (jornadaIgualTodos.value !== false) {
|
||||
selectedDays.value.forEach(d => { jornadaPorDia.value[d.value] = { inicio: jornadaStart.value, fim: jornadaEnd.value } })
|
||||
// Sync apenas Seg–Sex; Sáb e Dom têm horário próprio
|
||||
selectedDays.value
|
||||
.filter(d => d.value >= 1 && d.value <= 5)
|
||||
.forEach(d => { jornadaPorDia.value[d.value] = { inicio: jornadaStart.value, fim: jornadaEnd.value } })
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
@@ -208,10 +224,15 @@ function getPausasForDay (dayValue) {
|
||||
|
||||
// ── Toggle igual/diferente ─────────────────────────────────────
|
||||
function switchToIgual () {
|
||||
// Copia global para todos os dias (zera divergências por dia)
|
||||
if (isValidHHMM(jornadaStart.value) && isValidHHMM(jornadaEnd.value)) {
|
||||
selectedDays.value.forEach(d => {
|
||||
jornadaPorDia.value[d.value] = { inicio: jornadaStart.value, fim: jornadaEnd.value }
|
||||
// Sync apenas Seg–Sex; Sáb e Dom mantêm horário próprio
|
||||
selectedDays.value
|
||||
.filter(d => d.value >= 1 && d.value <= 5)
|
||||
.forEach(d => { jornadaPorDia.value[d.value] = { inicio: jornadaStart.value, fim: jornadaEnd.value } })
|
||||
// Inicializa Sáb/Dom com horário global se ainda não tiver valor
|
||||
;[6, 0].forEach(v => {
|
||||
if (workDays.value[v] && !jornadaPorDia.value[v]?.inicio)
|
||||
jornadaPorDia.value[v] = { inicio: jornadaStart.value, fim: jornadaEnd.value }
|
||||
})
|
||||
}
|
||||
// Copia pausas globais para todos os dias e usa apenas pausasGlobais
|
||||
@@ -423,6 +444,7 @@ async function saveJornada () {
|
||||
tenant_id: tenantId,
|
||||
pausas_semanais: pausasToSave,
|
||||
jornada_igual_todos: igualTodos,
|
||||
timezone: cfg.value.timezone || 'America/Sao_Paulo',
|
||||
setup_clinica_concluido: true,
|
||||
setup_clinica_concluido_em: cfg.value.setup_clinica_concluido_em || new Date().toISOString()
|
||||
}, { onConflict: 'owner_id' })
|
||||
@@ -431,7 +453,8 @@ async function saveJornada () {
|
||||
|
||||
// 2. regras semanais
|
||||
const rows = selectedDays.value.map(d => {
|
||||
const t = jornadaIgualTodos.value === false
|
||||
const isWeekend = d.value === 6 || d.value === 0
|
||||
const t = (jornadaIgualTodos.value === false || isWeekend)
|
||||
? (jornadaPorDia.value[d.value] || { inicio: jornadaStart.value, fim: jornadaEnd.value })
|
||||
: { inicio: jornadaStart.value, fim: jornadaEnd.value }
|
||||
return { owner_id: uid, tenant_id: tenantId, dia_semana: d.value, hora_inicio: normalizeTime(t.inicio), hora_fim: normalizeTime(t.fim), modalidade: 'ambos', ativo: true }
|
||||
@@ -797,7 +820,19 @@ const jornadaEndDate = computed({
|
||||
<div v-show="expandedCard === 'jornada'" class="cfg-card__body">
|
||||
<div class="border-t border-[var(--surface-border)] pt-4">
|
||||
|
||||
<!-- Início das sessões (alinhamento de horário) -->
|
||||
<!-- Fuso horário -->
|
||||
<div class="mb-5">
|
||||
<div class="cfg-label mb-2">Fuso horário</div>
|
||||
<Select
|
||||
v-model="cfg.timezone"
|
||||
:options="timezones"
|
||||
optionLabel="label"
|
||||
optionValue="value"
|
||||
class="w-full max-w-xs"
|
||||
placeholder="Selecione o fuso..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Dias da semana -->
|
||||
<div class="mb-5">
|
||||
<div class="cfg-label mb-2">Quais dias você trabalha?</div>
|
||||
@@ -837,23 +872,77 @@ const jornadaEndDate = computed({
|
||||
</div>
|
||||
|
||||
<!-- Igual para todos -->
|
||||
<div v-if="jornadaIgualTodos !== false" class="flex flex-wrap items-center gap-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm text-[var(--text-color-secondary)]">Das</span>
|
||||
<div class="w-32">
|
||||
<DatePicker v-model="jornadaStartDate" showIcon fluid iconDisplay="input" timeOnly hourFormat="24" :stepMinute="15" :manualInput="false">
|
||||
<template #inputicon="slotProps">
|
||||
<i class="pi pi-clock" @click="slotProps.clickCallback" />
|
||||
</template>
|
||||
</DatePicker>
|
||||
<div v-if="jornadaIgualTodos !== false" class="flex flex-col gap-3">
|
||||
<!-- Seg–Sex -->
|
||||
<div v-if="selectedWeekdays.length > 0" class="cfg-equal-group">
|
||||
<div class="cfg-equal-chips">
|
||||
<span v-for="d in selectedWeekdays" :key="d.value" class="day-chip day-chip--active">{{ d.short }}</span>
|
||||
</div>
|
||||
<span class="text-sm text-[var(--text-color-secondary)]">até</span>
|
||||
<div class="w-32">
|
||||
<DatePicker v-model="jornadaEndDate" showIcon fluid iconDisplay="input" timeOnly hourFormat="24" :stepMinute="15" :manualInput="false">
|
||||
<template #inputicon="slotProps">
|
||||
<i class="pi pi-clock" @click="slotProps.clickCallback" />
|
||||
</template>
|
||||
</DatePicker>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm text-[var(--text-color-secondary)]">Das</span>
|
||||
<div class="w-32">
|
||||
<DatePicker v-model="jornadaStartDate" showIcon fluid iconDisplay="input" timeOnly hourFormat="24" :stepMinute="15" :manualInput="false">
|
||||
<template #inputicon="slotProps"><i class="pi pi-clock" @click="slotProps.clickCallback" /></template>
|
||||
</DatePicker>
|
||||
</div>
|
||||
<span class="text-sm text-[var(--text-color-secondary)]">até</span>
|
||||
<div class="w-32">
|
||||
<DatePicker v-model="jornadaEndDate" showIcon fluid iconDisplay="input" timeOnly hourFormat="24" :stepMinute="15" :manualInput="false">
|
||||
<template #inputicon="slotProps"><i class="pi pi-clock" @click="slotProps.clickCallback" /></template>
|
||||
</DatePicker>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Sábado -->
|
||||
<div v-if="workDays[6]" class="cfg-equal-group">
|
||||
<div class="cfg-equal-chips">
|
||||
<span class="day-chip day-chip--active">Sáb</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm text-[var(--text-color-secondary)]">Das</span>
|
||||
<div class="w-32">
|
||||
<DatePicker
|
||||
:modelValue="hhmmToDate(jornadaPorDia[6]?.inicio)"
|
||||
@update:modelValue="v => { const h = dateToHHMM(v); if (h) jornadaPorDia[6] = { ...jornadaPorDia[6], inicio: h } }"
|
||||
showIcon fluid iconDisplay="input" timeOnly hourFormat="24" :stepMinute="15" :manualInput="false">
|
||||
<template #inputicon="slotProps"><i class="pi pi-clock" @click="slotProps.clickCallback" /></template>
|
||||
</DatePicker>
|
||||
</div>
|
||||
<span class="text-sm text-[var(--text-color-secondary)]">até</span>
|
||||
<div class="w-32">
|
||||
<DatePicker
|
||||
:modelValue="hhmmToDate(jornadaPorDia[6]?.fim)"
|
||||
@update:modelValue="v => { const h = dateToHHMM(v); if (h) jornadaPorDia[6] = { ...jornadaPorDia[6], fim: h } }"
|
||||
showIcon fluid iconDisplay="input" timeOnly hourFormat="24" :stepMinute="15" :manualInput="false">
|
||||
<template #inputicon="slotProps"><i class="pi pi-clock" @click="slotProps.clickCallback" /></template>
|
||||
</DatePicker>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Domingo -->
|
||||
<div v-if="workDays[0]" class="cfg-equal-group">
|
||||
<div class="cfg-equal-chips">
|
||||
<span class="day-chip day-chip--active">Dom</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm text-[var(--text-color-secondary)]">Das</span>
|
||||
<div class="w-32">
|
||||
<DatePicker
|
||||
:modelValue="hhmmToDate(jornadaPorDia[0]?.inicio)"
|
||||
@update:modelValue="v => { const h = dateToHHMM(v); if (h) jornadaPorDia[0] = { ...jornadaPorDia[0], inicio: h } }"
|
||||
showIcon fluid iconDisplay="input" timeOnly hourFormat="24" :stepMinute="15" :manualInput="false">
|
||||
<template #inputicon="slotProps"><i class="pi pi-clock" @click="slotProps.clickCallback" /></template>
|
||||
</DatePicker>
|
||||
</div>
|
||||
<span class="text-sm text-[var(--text-color-secondary)]">até</span>
|
||||
<div class="w-32">
|
||||
<DatePicker
|
||||
:modelValue="hhmmToDate(jornadaPorDia[0]?.fim)"
|
||||
@update:modelValue="v => { const h = dateToHHMM(v); if (h) jornadaPorDia[0] = { ...jornadaPorDia[0], fim: h } }"
|
||||
showIcon fluid iconDisplay="input" timeOnly hourFormat="24" :stepMinute="15" :manualInput="false">
|
||||
<template #inputicon="slotProps"><i class="pi pi-clock" @click="slotProps.clickCallback" /></template>
|
||||
</DatePicker>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1306,6 +1395,8 @@ const jornadaEndDate = computed({
|
||||
.day-chip:hover { border-color: var(--primary-color); }
|
||||
.day-chip--active { background: var(--primary-color); border-color: var(--primary-color); color: #fff; }
|
||||
.day-chip--sm { padding: .2rem .55rem; font-size: .75rem; }
|
||||
.cfg-equal-group { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; }
|
||||
.cfg-equal-chips { display: flex; flex-wrap: wrap; gap: 0.3rem; min-width: 200px; }
|
||||
|
||||
/* ── Toggle opções ──────────────────────────────────────────── */
|
||||
.toggle-opt {
|
||||
|
||||
Reference in New Issue
Block a user