iachat/app/javascript/dashboard/store/captain/notificationTemplates.js
Rodrigo Borba 44908f32d1 feat: sistema de notificações de reserva com templates configuráveis
- Adiciona check_in_at/duration_hours ao schema do tool CreateReservationIntent
  para que a IA capture o horário EXATO de chegada informado pelo cliente
- Cria captain_notification_templates: label, content, timing_minutes,
  timing_direction (before/after), active, position
- Implementa SendNotificationService com interpolação de variáveis
  (guest_name, check_in_time, check_out_time, suite_name, unit_name)
- Implementa NotificationScannerJob (Sidekiq-cron a cada 5min) com
  janela de tolerância de ±5min e idempotência via metadata JSONB
- API REST: /captain/units/:unit_id/notification_templates (CRUD)
- Store Vuex captainNotificationTemplates + API client
- UI: página de gestão de templates com editor inline e botão '+'
- Configura rota captain_settings_notifications
- i18n PT/EN para todas as strings novas
- Rubocop e ESLint: zero offenses
2026-03-01 21:53:11 -03:00

105 lines
2.6 KiB
JavaScript

import CaptainNotificationTemplatesAPI from 'dashboard/api/captain/notificationTemplates';
import { throwErrorMessage } from 'dashboard/store/utils/api';
const state = {
templates: [],
uiFlags: {
isFetching: false,
isCreating: false,
isUpdating: false,
isDeleting: false,
},
};
const getters = {
getTemplates: $state => $state.templates,
getUIFlags: $state => $state.uiFlags,
};
const mutations = {
SET_TEMPLATES($state, templates) {
$state.templates = templates;
},
ADD_TEMPLATE($state, template) {
$state.templates.push(template);
},
UPDATE_TEMPLATE($state, updated) {
const index = $state.templates.findIndex(t => t.id === updated.id);
if (index !== -1) $state.templates.splice(index, 1, updated);
},
DELETE_TEMPLATE($state, id) {
$state.templates = $state.templates.filter(t => t.id !== id);
},
SET_UI_FLAG($state, flags) {
$state.uiFlags = { ...$state.uiFlags, ...flags };
},
};
const actions = {
fetch: async ({ commit }, unitId) => {
commit('SET_UI_FLAG', { isFetching: true });
try {
const { data } =
await CaptainNotificationTemplatesAPI.getTemplates(unitId);
commit('SET_TEMPLATES', data);
} catch (error) {
throwErrorMessage(error);
} finally {
commit('SET_UI_FLAG', { isFetching: false });
}
},
create: async ({ commit }, { unitId, ...templateData }) => {
commit('SET_UI_FLAG', { isCreating: true });
try {
const { data } = await CaptainNotificationTemplatesAPI.createTemplate(
unitId,
templateData
);
commit('ADD_TEMPLATE', data);
return data;
} catch (error) {
return throwErrorMessage(error);
} finally {
commit('SET_UI_FLAG', { isCreating: false });
}
},
update: async ({ commit }, { unitId, id, ...templateData }) => {
commit('SET_UI_FLAG', { isUpdating: true });
try {
const { data } = await CaptainNotificationTemplatesAPI.updateTemplate(
unitId,
id,
templateData
);
commit('UPDATE_TEMPLATE', data);
return data;
} catch (error) {
return throwErrorMessage(error);
} finally {
commit('SET_UI_FLAG', { isUpdating: false });
}
},
delete: async ({ commit }, { unitId, id }) => {
commit('SET_UI_FLAG', { isDeleting: true });
try {
await CaptainNotificationTemplatesAPI.deleteTemplate(unitId, id);
commit('DELETE_TEMPLATE', id);
} catch (error) {
throwErrorMessage(error);
} finally {
commit('SET_UI_FLAG', { isDeleting: false });
}
},
};
export default {
namespaced: true,
state,
getters,
mutations,
actions,
};