@ossy/booking 1.13.0 → 1.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -2
- package/src/availability-engine.js +118 -0
- package/src/availability-engine.spec.js +291 -0
- package/src/availability.resource.js +6 -0
- package/src/booking-cancellation.email.jsx +47 -0
- package/src/booking-confirmation.email.jsx +107 -0
- package/src/booking-reminder.email.jsx +69 -0
- package/src/booking-request.email.jsx +96 -0
- package/src/cancel-booking.action.js +61 -0
- package/src/confirm-booking.action.js +82 -0
- package/src/create-booking.action.js +156 -0
- package/src/decline-booking.action.js +68 -0
- package/src/get-available-slots.action.js +73 -0
- package/src/index.js +2 -0
- package/src/public-booking.page.jsx +739 -0
- package/src/send-booking-reminder.task.js +76 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { ResourcesQueries } from '@ossy/resources'
|
|
2
|
+
import BookingReminderEmail from './booking-reminder.email.jsx'
|
|
3
|
+
|
|
4
|
+
export const metadata = {
|
|
5
|
+
id: 'booking/send-reminder',
|
|
6
|
+
schedule: '0 * * * *', // every hour — checks for bookings starting ~24h from now
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function run({ sdk, log, integrations }) {
|
|
10
|
+
const now = Date.now()
|
|
11
|
+
const windowStart = new Date(now + 23 * 60 * 60 * 1000).toISOString()
|
|
12
|
+
const windowEnd = new Date(now + 25 * 60 * 60 * 1000).toISOString()
|
|
13
|
+
|
|
14
|
+
log?.info(`[booking/send-reminder] Checking bookings between ${windowStart} and ${windowEnd}`)
|
|
15
|
+
|
|
16
|
+
const allBookings = await ResourcesQueries.GetResources({
|
|
17
|
+
type: '@ossy/booking/booking',
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const upcoming = allBookings.filter(b => {
|
|
21
|
+
const { status, startsAt, reminderSentAt } = b.content ?? {}
|
|
22
|
+
if (status !== 'confirmed') return false
|
|
23
|
+
if (reminderSentAt) return false
|
|
24
|
+
return startsAt >= windowStart && startsAt <= windowEnd
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
log?.info(`[booking/send-reminder] Found ${upcoming.length} bookings needing reminders`)
|
|
28
|
+
|
|
29
|
+
const emailClient = integrations?.get?.('email')
|
|
30
|
+
if (!emailClient) {
|
|
31
|
+
log?.warn('[booking/send-reminder] No email integration available, skipping')
|
|
32
|
+
return { sent: 0 }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let sent = 0
|
|
36
|
+
|
|
37
|
+
for (const booking of upcoming) {
|
|
38
|
+
const { clientName, clientEmail, consultantId, startsAt, duration } = booking.content ?? {}
|
|
39
|
+
|
|
40
|
+
if (!clientEmail) continue
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
await emailClient.sendTemplate(
|
|
44
|
+
BookingReminderEmail,
|
|
45
|
+
{
|
|
46
|
+
clientName: clientName ?? 'Kund',
|
|
47
|
+
consultantName: null,
|
|
48
|
+
startAt: startsAt,
|
|
49
|
+
duration: duration ?? 60,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
to: clientEmail,
|
|
53
|
+
from: 'noreply@ossy.se',
|
|
54
|
+
subject: 'Påminnelse: din bokning imorgon',
|
|
55
|
+
},
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
// Mark reminder as sent via SDK if available, otherwise skip to avoid
|
|
59
|
+
// needing direct DB writes in a scheduled task
|
|
60
|
+
if (sdk) {
|
|
61
|
+
await sdk.actions.run('resources/update-content', {
|
|
62
|
+
resourceId: booking.id,
|
|
63
|
+
content: { ...booking.content, reminderSentAt: new Date().toISOString() },
|
|
64
|
+
workspaceId: consultantId,
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
sent++
|
|
69
|
+
log?.info(`[booking/send-reminder] Reminder sent to ${clientEmail}`)
|
|
70
|
+
} catch (err) {
|
|
71
|
+
log?.error(`[booking/send-reminder] Failed to send reminder to ${clientEmail}`, err)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return { sent }
|
|
76
|
+
}
|