feat(lifecycle): parent view with TabBar + 3 stub children routes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
bc85ec0a67
commit
65a76ed59d
@ -17,6 +17,10 @@ import ResponsesIndex from './responses/Index.vue';
|
||||
import ResponsesPendingIndex from './responses/Pending.vue';
|
||||
import CustomToolsIndex from './tools/Index.vue';
|
||||
import ReservationsIndex from './reservations/Index.vue';
|
||||
import LifecycleIndex from './lifecycle/Index.vue';
|
||||
import LifecycleRules from './lifecycle/Rules.vue';
|
||||
import LifecycleSettings from './lifecycle/Settings.vue';
|
||||
import LifecycleHistory from './lifecycle/History.vue';
|
||||
|
||||
const meta = {
|
||||
permissions: ['administrator', 'agent'],
|
||||
@ -137,4 +141,30 @@ export const routes = [
|
||||
name: 'captain_reservations_index',
|
||||
meta,
|
||||
},
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/captain/lifecycle'),
|
||||
component: LifecycleIndex,
|
||||
meta,
|
||||
redirect: { name: 'captain_lifecycle_rules' },
|
||||
children: [
|
||||
{
|
||||
path: 'rules',
|
||||
component: LifecycleRules,
|
||||
name: 'captain_lifecycle_rules',
|
||||
meta,
|
||||
},
|
||||
{
|
||||
path: 'settings',
|
||||
component: LifecycleSettings,
|
||||
name: 'captain_lifecycle_settings',
|
||||
meta,
|
||||
},
|
||||
{
|
||||
path: 'history',
|
||||
component: LifecycleHistory,
|
||||
name: 'captain_lifecycle_history',
|
||||
meta,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="p-6">
|
||||
<h2 class="text-lg font-semibold">
|
||||
{{ t('CAPTAIN_LIFECYCLE.TABS.HISTORY') }}
|
||||
</h2>
|
||||
<!-- Implementation in Task 13 -->
|
||||
</div>
|
||||
</template>
|
||||
@ -0,0 +1,52 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import PageLayout from 'dashboard/components-next/captain/PageLayout.vue';
|
||||
import TabBar from 'dashboard/components-next/tabbar/TabBar.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const tabs = computed(() => [
|
||||
{ name: 'captain_lifecycle_rules', label: t('CAPTAIN_LIFECYCLE.TABS.RULES') },
|
||||
{
|
||||
name: 'captain_lifecycle_settings',
|
||||
label: t('CAPTAIN_LIFECYCLE.TABS.SETTINGS'),
|
||||
},
|
||||
{
|
||||
name: 'captain_lifecycle_history',
|
||||
label: t('CAPTAIN_LIFECYCLE.TABS.HISTORY'),
|
||||
},
|
||||
]);
|
||||
|
||||
const activeIndex = computed(() =>
|
||||
Math.max(
|
||||
0,
|
||||
tabs.value.findIndex(tab => tab.name === route.name)
|
||||
)
|
||||
);
|
||||
|
||||
const handleTabChanged = tab => {
|
||||
router.push({ name: tab.name, params: route.params });
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PageLayout
|
||||
:header-title="t('CAPTAIN_LIFECYCLE.HEADER')"
|
||||
:show-assistant-switcher="false"
|
||||
:show-pagination-footer="false"
|
||||
:show-know-more="false"
|
||||
>
|
||||
<div class="flex flex-col gap-4">
|
||||
<TabBar
|
||||
:tabs="tabs"
|
||||
:initial-active-tab="activeIndex"
|
||||
@tab-changed="handleTabChanged"
|
||||
/>
|
||||
<router-view />
|
||||
</div>
|
||||
</PageLayout>
|
||||
</template>
|
||||
@ -0,0 +1,14 @@
|
||||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="p-6">
|
||||
<h2 class="text-lg font-semibold">
|
||||
{{ t('CAPTAIN_LIFECYCLE.TABS.RULES') }}
|
||||
</h2>
|
||||
<!-- Implementation in Task 15 -->
|
||||
</div>
|
||||
</template>
|
||||
@ -0,0 +1,14 @@
|
||||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="p-6">
|
||||
<h2 class="text-lg font-semibold">
|
||||
{{ t('CAPTAIN_LIFECYCLE.TABS.SETTINGS') }}
|
||||
</h2>
|
||||
<!-- Implementation in Task 14 -->
|
||||
</div>
|
||||
</template>
|
||||
@ -0,0 +1,92 @@
|
||||
export const EVENTS = [
|
||||
{
|
||||
value: 'reservation.confirmed',
|
||||
labelKey: 'CAPTAIN_LIFECYCLE.RULES.WIZARD.EVENTS.RESERVATION_CONFIRMED',
|
||||
},
|
||||
{
|
||||
value: 'checkin.scheduled_at',
|
||||
labelKey: 'CAPTAIN_LIFECYCLE.RULES.WIZARD.EVENTS.CHECKIN_SCHEDULED_AT',
|
||||
},
|
||||
{
|
||||
value: 'checkout.scheduled_at',
|
||||
labelKey: 'CAPTAIN_LIFECYCLE.RULES.WIZARD.EVENTS.CHECKOUT_SCHEDULED_AT',
|
||||
},
|
||||
{
|
||||
value: 'reservation.cancelled',
|
||||
labelKey: 'CAPTAIN_LIFECYCLE.RULES.WIZARD.EVENTS.RESERVATION_CANCELLED',
|
||||
},
|
||||
{
|
||||
value: 'reservation.no_show',
|
||||
labelKey: 'CAPTAIN_LIFECYCLE.RULES.WIZARD.EVENTS.RESERVATION_NO_SHOW',
|
||||
},
|
||||
];
|
||||
|
||||
export const MESSAGE_TYPES = [
|
||||
{
|
||||
value: 'text',
|
||||
labelKey: 'CAPTAIN_LIFECYCLE.RULES.WIZARD.MESSAGE_TYPES.TEXT',
|
||||
},
|
||||
{
|
||||
value: 'buttons',
|
||||
labelKey: 'CAPTAIN_LIFECYCLE.RULES.WIZARD.MESSAGE_TYPES.BUTTONS',
|
||||
},
|
||||
{
|
||||
value: 'list',
|
||||
labelKey: 'CAPTAIN_LIFECYCLE.RULES.WIZARD.MESSAGE_TYPES.LIST',
|
||||
},
|
||||
{
|
||||
value: 'url_button',
|
||||
labelKey: 'CAPTAIN_LIFECYCLE.RULES.WIZARD.MESSAGE_TYPES.URL_BUTTON',
|
||||
},
|
||||
];
|
||||
|
||||
export const OFFSET_UNITS = [
|
||||
{ value: 'minutes', factor: 1 },
|
||||
{ value: 'hours', factor: 60 },
|
||||
{ value: 'days', factor: 1440 },
|
||||
];
|
||||
|
||||
export const AVAILABLE_VARIABLES = [
|
||||
{ key: 'customer.first_name', descKey: 'Primeiro nome do cliente' },
|
||||
{ key: 'customer.name', descKey: 'Nome completo' },
|
||||
{ key: 'customer.phone', descKey: 'Telefone' },
|
||||
{ key: 'reservation.suite', descKey: 'Suíte' },
|
||||
{ key: 'reservation.unit_name', descKey: 'Nome da unidade' },
|
||||
{ key: 'reservation.check_in_at', descKey: 'Check-in' },
|
||||
{ key: 'reservation.check_out_at', descKey: 'Check-out' },
|
||||
{ key: 'reservation.amount', descKey: 'Valor' },
|
||||
{ key: 'hotel.wifi_password', descKey: 'Senha do WiFi' },
|
||||
{ key: 'hotel.menu_link', descKey: 'Link do cardápio' },
|
||||
{ key: 'hotel.google_review_link', descKey: 'Link de review' },
|
||||
{ key: 'hotel.address', descKey: 'Endereço' },
|
||||
];
|
||||
|
||||
export const RULE_TEMPLATES = [
|
||||
{
|
||||
id: 'precheckin_reminder',
|
||||
name: 'Lembrete 10min antes do check-in',
|
||||
event: 'checkin.scheduled_at',
|
||||
offset_minutes: -10,
|
||||
message_type: 'text',
|
||||
message_body:
|
||||
'Oi {{ customer.first_name }}! Seu check-in é em 10 minutos na suíte {{ reservation.suite }}. Wifi: {{ hotel.wifi_password }}',
|
||||
},
|
||||
{
|
||||
id: 'welcome_instay',
|
||||
name: 'Boas-vindas após check-in',
|
||||
event: 'checkin.scheduled_at',
|
||||
offset_minutes: 15,
|
||||
message_type: 'text',
|
||||
message_body:
|
||||
'Seja bem-vindo(a), {{ customer.first_name }}! Qualquer coisa, só chamar. Cardápio: {{ hotel.menu_link }}',
|
||||
},
|
||||
{
|
||||
id: 'review_request',
|
||||
name: 'Pedido de review no Google',
|
||||
event: 'checkout.scheduled_at',
|
||||
offset_minutes: 120,
|
||||
message_type: 'url_button',
|
||||
message_body:
|
||||
'{{ customer.first_name }}, adoraríamos saber como foi sua estadia. Se puder, deixa um review pra gente: {{ hotel.google_review_link }}',
|
||||
},
|
||||
];
|
||||
Loading…
Reference in New Issue
Block a user