@7365admin1/core 3.52.2-staging.234 → 3.52.2-staging.235
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/dist/handlebars/approve-drive-in.hbs +154 -67
- package/dist/handlebars/approve-walk-in.hbs +154 -67
- package/dist/index.js +59 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +59 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1,79 +1,166 @@
|
|
|
1
|
-
|
|
1
|
+
{{! Visitor invitation email.
|
|
2
|
+
|
|
3
|
+
Email-client rules this file follows -- please keep them when editing:
|
|
4
|
+
* layout is <table>-based; flexbox and grid do not work in Outlook
|
|
5
|
+
* every style is inline; <style> blocks are stripped by Gmail
|
|
6
|
+
* no external CSS or web fonts
|
|
7
|
+
* `isInviteEmail` gates the resident-invite rows. The legacy
|
|
8
|
+
`residentAppInvitePreRegister` sender renders this same file from a
|
|
9
|
+
different document shape and sets none of those keys -- Handlebars
|
|
10
|
+
prints a missing key as an empty string, so without the guard that
|
|
11
|
+
email would grow a column of blank cells.
|
|
12
|
+
}}
|
|
13
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="background-color: #eef1f4; margin: 0; padding: 24px 12px;">
|
|
2
14
|
<tr>
|
|
3
|
-
<td style="vertical-align:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<div style="display: flex; justify-content: center;">
|
|
7
|
-
<img src="{{logo}}" style="width: 190px; height: 50px;" />
|
|
8
|
-
</div>
|
|
9
|
-
</div>
|
|
10
|
-
<div style="margin-bottom: 16px; color: #052439; ">
|
|
11
|
-
<p style="color: #052439; font-weight: 600; font-size: 32px; line-height: 30px; text-align: center; padding: 16px;">Hey
|
|
12
|
-
{{name}},</p>
|
|
13
|
-
<p style="text-align: center;">You are now ready to check in upon arrival on {{arrivalDate}}.</p>
|
|
14
|
-
</div>
|
|
15
|
-
<a href="{{qrLink}}" style="text-decoration: none"><div
|
|
16
|
-
style="margin-top: 16px; padding: 5px; background-color: #4caf50; border-radius: 16px; text-align: center;"
|
|
17
|
-
>
|
|
18
|
-
<p style="color: white; font-weight: bold;">QR code Link (Click Here)</p>
|
|
19
|
-
</div></a>
|
|
15
|
+
<td align="center" style="vertical-align: top;">
|
|
16
|
+
|
|
17
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="600" style="width: 100%; max-width: 600px; background-color: #ffffff; border-radius: 14px; overflow: hidden; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;">
|
|
20
18
|
|
|
21
|
-
<
|
|
22
|
-
<
|
|
23
|
-
|
|
19
|
+
<tr>
|
|
20
|
+
<td align="center" style="background-color: #052439; padding: 22px 24px;">
|
|
21
|
+
<img src="{{logo}}" alt="Seven365" width="190" height="50" style="width: 190px; height: 50px; border: 0; display: block; color: #ffffff; font-family: Helvetica, Arial, sans-serif; font-size: 15px; font-weight: 700;" />
|
|
22
|
+
</td>
|
|
23
|
+
</tr>
|
|
24
24
|
|
|
25
|
-
<
|
|
26
|
-
<
|
|
27
|
-
|
|
25
|
+
<tr>
|
|
26
|
+
<td style="padding: 32px 28px 8px 28px; text-align: center;">
|
|
27
|
+
<p style="margin: 0; color: #052439; font-weight: 700; font-size: 27px; line-height: 34px;">Hey {{name}},</p>
|
|
28
|
+
<p style="margin: 10px 0 0 0; color: #5b6b78; font-size: 15px; line-height: 22px;">You are now ready to check in upon arrival on <span style="color: #052439; font-weight: 600;">{{arrivalDate}}</span>.</p>
|
|
29
|
+
</td>
|
|
30
|
+
</tr>
|
|
28
31
|
|
|
29
|
-
<
|
|
30
|
-
<
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
<tr>
|
|
33
|
+
<td style="padding: 22px 28px 0 28px;">
|
|
34
|
+
<a href="{{qrLink}}" style="display: block; background-color: #35a745; color: #ffffff; font-size: 16px; font-weight: 700; text-decoration: none; text-align: center; padding: 15px 20px; border-radius: 10px;">View My QR Code ( Click Here )</a>
|
|
35
|
+
{{#if statusLabel}}
|
|
36
|
+
{{! Whether the QR is usable yet. Sits under the button so it is read
|
|
37
|
+
before the tap, not after. `statusColor` is inlined from the
|
|
38
|
+
context because Handlebars has no helpers registered here. }}
|
|
39
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="width: 100%;">
|
|
40
|
+
<tr>
|
|
41
|
+
<td align="center" style="padding: 14px 0 0 0;">
|
|
42
|
+
<span style="color: #7b8a95; font-size: 12px; letter-spacing: 0.4px; text-transform: uppercase; font-weight: 700;">QR Status</span>
|
|
43
|
+
<span style="display: inline-block; background-color: {{statusColor}}; color: #ffffff; font-size: 13px; font-weight: 700; padding: 5px 14px; border-radius: 999px; margin-left: 8px;">{{statusLabel}}</span>
|
|
44
|
+
</td>
|
|
35
45
|
</tr>
|
|
46
|
+
</table>
|
|
47
|
+
{{/if}}
|
|
48
|
+
<p style="margin: 12px 0 0 0; color: #7b8a95; font-size: 13px; line-height: 19px; text-align: center;">Please present the QR code at the pedestrian entrance for access.</p>
|
|
49
|
+
</td>
|
|
50
|
+
</tr>
|
|
51
|
+
|
|
52
|
+
<tr>
|
|
53
|
+
<td style="padding: 26px 28px 0 28px;">
|
|
54
|
+
<p style="margin: 0 0 10px 0; color: #052439; font-size: 12px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase;">Visitor Information</p>
|
|
36
55
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
<td style="
|
|
56
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="width: 100%; border-collapse: collapse;">
|
|
57
|
+
<tr>
|
|
58
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Name</td>
|
|
59
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{name}}</td>
|
|
60
|
+
</tr>
|
|
61
|
+
{{#if isInviteEmail}}{{#if isContractor}}
|
|
62
|
+
<tr>
|
|
63
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Company</td>
|
|
64
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{company}}</td>
|
|
65
|
+
</tr>
|
|
66
|
+
<tr>
|
|
67
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Contractor Type</td>
|
|
68
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{contractorTypeLabel}}</td>
|
|
69
|
+
</tr>
|
|
70
|
+
{{/if}}{{/if}}
|
|
71
|
+
<tr>
|
|
72
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Tenant/Resident Address</td>
|
|
73
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{address}}</td>
|
|
74
|
+
</tr>
|
|
75
|
+
<tr>
|
|
76
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Contact No.</td>
|
|
77
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{contactNumber}}</td>
|
|
78
|
+
</tr>
|
|
79
|
+
<tr>
|
|
80
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Email</td>
|
|
81
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right; word-break: break-all;">{{email}}</td>
|
|
82
|
+
</tr>
|
|
83
|
+
{{#if isInviteEmail}}
|
|
84
|
+
<tr>
|
|
85
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Vehicle Plate No.</td>
|
|
86
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{plateNumber}}</td>
|
|
87
|
+
</tr>
|
|
88
|
+
<tr>
|
|
89
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Overnight Parking</td>
|
|
90
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{overnightParking}}</td>
|
|
40
91
|
</tr>
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
<td style="
|
|
92
|
+
{{/if}}
|
|
93
|
+
<tr>
|
|
94
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Arrival Date</td>
|
|
95
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{arrivalDate}}</td>
|
|
44
96
|
</tr>
|
|
45
|
-
<tr
|
|
46
|
-
<td style="
|
|
47
|
-
<td style="
|
|
97
|
+
<tr>
|
|
98
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Arrival Time</td>
|
|
99
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{arrivalTime}}</td>
|
|
48
100
|
</tr>
|
|
101
|
+
<tr>
|
|
102
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Duration</td>
|
|
103
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{duration}}</td>
|
|
104
|
+
</tr>
|
|
105
|
+
{{#if isInviteEmail}}
|
|
106
|
+
<tr>
|
|
107
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Number of Passenger</td>
|
|
108
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{numberOfPassengers}}</td>
|
|
109
|
+
</tr>
|
|
110
|
+
{{/if}}
|
|
111
|
+
{{! Stacked rather than right-aligned: a purpose can run long, and a
|
|
112
|
+
wrapped right-aligned value reads as ragged noise. }}
|
|
113
|
+
<tr>
|
|
114
|
+
<td colspan="2" style="padding: 11px 0 0 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Purpose of Visit</td>
|
|
115
|
+
</tr>
|
|
116
|
+
<tr>
|
|
117
|
+
<td colspan="2" style="padding: 3px 0 11px 0; color: #052439; font-size: 14px; font-weight: 600; line-height: 21px;">{{purposeOfVisit}}</td>
|
|
118
|
+
</tr>
|
|
119
|
+
</table>
|
|
120
|
+
</td>
|
|
121
|
+
</tr>
|
|
122
|
+
|
|
123
|
+
{{#if hasMembers}}
|
|
124
|
+
<tr>
|
|
125
|
+
<td style="padding: 26px 28px 0 28px;">
|
|
126
|
+
<p style="margin: 0 0 12px 0; color: #052439; font-size: 12px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase;">Accompanying Members</p>
|
|
127
|
+
|
|
128
|
+
{{#each members}}
|
|
129
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="width: 100%; background-color: #f5f8fa; border: 1px solid #e7ecf0; border-radius: 10px; margin-bottom: 10px;">
|
|
130
|
+
<tr>
|
|
131
|
+
<td style="padding: 14px 16px;">
|
|
132
|
+
<p style="margin: 0 0 2px 0; color: #35a745; font-size: 11px; font-weight: 700; letter-spacing: 0.8px; text-transform: uppercase;">Member {{position}}</p>
|
|
133
|
+
<p style="margin: 0 0 8px 0; color: #052439; font-size: 16px; font-weight: 700;">{{name}}</p>
|
|
134
|
+
|
|
135
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="width: 100%; border-collapse: collapse;">
|
|
136
|
+
<tr>
|
|
137
|
+
<td style="padding: 5px 0; color: #6b7c8a; font-size: 13px;">NRIC / Passport No.</td>
|
|
138
|
+
<td style="padding: 5px 0; color: #052439; font-size: 13px; font-weight: 600; text-align: right;">{{nric}}</td>
|
|
139
|
+
</tr>
|
|
140
|
+
<tr>
|
|
141
|
+
<td style="padding: 5px 0; color: #6b7c8a; font-size: 13px;">Contact No.</td>
|
|
142
|
+
<td style="padding: 5px 0; color: #052439; font-size: 13px; font-weight: 600; text-align: right;">{{contact}}</td>
|
|
143
|
+
</tr>
|
|
144
|
+
<tr>
|
|
145
|
+
<td style="padding: 5px 0; color: #6b7c8a; font-size: 13px;">Vehicle Plate No.</td>
|
|
146
|
+
<td style="padding: 5px 0; color: #052439; font-size: 13px; font-weight: 600; text-align: right;">{{plateNumber}}</td>
|
|
147
|
+
</tr>
|
|
148
|
+
</table>
|
|
149
|
+
</td>
|
|
150
|
+
</tr>
|
|
151
|
+
</table>
|
|
152
|
+
{{/each}}
|
|
153
|
+
</td>
|
|
154
|
+
</tr>
|
|
155
|
+
{{/if}}
|
|
156
|
+
|
|
157
|
+
<tr>
|
|
158
|
+
<td style="padding: 26px 28px 28px 28px;">
|
|
159
|
+
<p style="margin: 0; padding-top: 18px; border-top: 1px solid #e7ecf0; color: #90a0ab; font-size: 12px; line-height: 18px; text-align: center;">This invitation was sent to you by your host.<br />© Seven365 Pte. Ltd.</p>
|
|
160
|
+
</td>
|
|
161
|
+
</tr>
|
|
49
162
|
|
|
50
|
-
|
|
51
|
-
<td style="text-align: left; font-weight: bold; padding: 8px;">Arrival Date</td>
|
|
52
|
-
<td style="text-align: right; padding: 8px;">{{arrivalDate}}</td>
|
|
53
|
-
</tr>
|
|
54
|
-
<tr style="border-bottom: 1px solid gray; padding: 20px;">
|
|
55
|
-
<td style="text-align: left; font-weight: bold; padding: 8px;">Arrival Time</td>
|
|
56
|
-
<td style="text-align: right; padding: 8px;">{{arrivalTime}}</td>
|
|
57
|
-
</tr>
|
|
58
|
-
<tr style="border-bottom: 1px solid gray; padding: 20px;">
|
|
59
|
-
<td style="text-align: left; font-weight: bold; padding: 8px;">Duration</td>
|
|
60
|
-
<td style="text-align: right; padding: 8px;">{{duration}}</td>
|
|
61
|
-
</tr>
|
|
62
|
-
<tr style=" padding: 20px;">
|
|
63
|
-
<td style="text-align: left; font-weight: bold; padding: 8px;">Purpose of Visit</td>
|
|
64
|
-
</tr>
|
|
65
|
-
<tr style="padding: 20px;"><td style="text-align: right; padding: 8px;">{{purposeOfVisit}}</td></tr>
|
|
66
|
-
</tbody>
|
|
67
|
-
</table>
|
|
68
|
-
</div>
|
|
69
|
-
<footer height="70" style="padding: 0; bottom: 0; left: 0; right: 0; z-index: 10; background-color: #fff;">
|
|
70
|
-
<div style="padding: 12px; max-width: 600px; margin-left: auto; margin-right: auto;">
|
|
71
|
-
<div style="text-align: center;">
|
|
72
|
-
<span style="font-size: 16px;">© 2024 powered by Seven365 Pte. Ltd. v.1</span>
|
|
73
|
-
</div>
|
|
74
|
-
</div>
|
|
75
|
-
</footer>
|
|
76
|
-
</div>
|
|
163
|
+
</table>
|
|
77
164
|
</td>
|
|
78
165
|
</tr>
|
|
79
|
-
</table>
|
|
166
|
+
</table>
|
|
@@ -1,79 +1,166 @@
|
|
|
1
|
-
|
|
1
|
+
{{! Visitor invitation email.
|
|
2
|
+
|
|
3
|
+
Email-client rules this file follows -- please keep them when editing:
|
|
4
|
+
* layout is <table>-based; flexbox and grid do not work in Outlook
|
|
5
|
+
* every style is inline; <style> blocks are stripped by Gmail
|
|
6
|
+
* no external CSS or web fonts
|
|
7
|
+
* `isInviteEmail` gates the resident-invite rows. The legacy
|
|
8
|
+
`residentAppInvitePreRegister` sender renders this same file from a
|
|
9
|
+
different document shape and sets none of those keys -- Handlebars
|
|
10
|
+
prints a missing key as an empty string, so without the guard that
|
|
11
|
+
email would grow a column of blank cells.
|
|
12
|
+
}}
|
|
13
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="background-color: #eef1f4; margin: 0; padding: 24px 12px;">
|
|
2
14
|
<tr>
|
|
3
|
-
<td style="vertical-align:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<div style="display: flex; justify-content: center;">
|
|
7
|
-
<img src="{{logo}}" style="width: 190px; height: 50px;" />
|
|
8
|
-
</div>
|
|
9
|
-
</div>
|
|
10
|
-
<div style="margin-bottom: 16px; color: #052439; ">
|
|
11
|
-
<p style="color: #052439; font-weight: 600; font-size: 32px; line-height: 30px; text-align: center; padding: 16px;">Hey
|
|
12
|
-
{{name}},</p>
|
|
13
|
-
<p style="text-align: center;">You are now ready to check in upon arrival on {{arrivalDate}}.</p>
|
|
14
|
-
</div>
|
|
15
|
-
<a href="{{qrLink}}" style="text-decoration: none"><div
|
|
16
|
-
style="margin-top: 16px; padding: 5px; background-color: #4caf50; border-radius: 16px; text-align: center;"
|
|
17
|
-
>
|
|
18
|
-
<p style="color: white; font-weight: bold;">QR code Link (Click Here)</p>
|
|
19
|
-
</div></a>
|
|
15
|
+
<td align="center" style="vertical-align: top;">
|
|
16
|
+
|
|
17
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="600" style="width: 100%; max-width: 600px; background-color: #ffffff; border-radius: 14px; overflow: hidden; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;">
|
|
20
18
|
|
|
21
|
-
<
|
|
22
|
-
<
|
|
23
|
-
|
|
19
|
+
<tr>
|
|
20
|
+
<td align="center" style="background-color: #052439; padding: 22px 24px;">
|
|
21
|
+
<img src="{{logo}}" alt="Seven365" width="190" height="50" style="width: 190px; height: 50px; border: 0; display: block; color: #ffffff; font-family: Helvetica, Arial, sans-serif; font-size: 15px; font-weight: 700;" />
|
|
22
|
+
</td>
|
|
23
|
+
</tr>
|
|
24
24
|
|
|
25
|
-
<
|
|
26
|
-
<
|
|
27
|
-
|
|
25
|
+
<tr>
|
|
26
|
+
<td style="padding: 32px 28px 8px 28px; text-align: center;">
|
|
27
|
+
<p style="margin: 0; color: #052439; font-weight: 700; font-size: 27px; line-height: 34px;">Hey {{name}},</p>
|
|
28
|
+
<p style="margin: 10px 0 0 0; color: #5b6b78; font-size: 15px; line-height: 22px;">You are now ready to check in upon arrival on <span style="color: #052439; font-weight: 600;">{{arrivalDate}}</span>.</p>
|
|
29
|
+
</td>
|
|
30
|
+
</tr>
|
|
28
31
|
|
|
29
|
-
<
|
|
30
|
-
<
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
<tr>
|
|
33
|
+
<td style="padding: 22px 28px 0 28px;">
|
|
34
|
+
<a href="{{qrLink}}" style="display: block; background-color: #35a745; color: #ffffff; font-size: 16px; font-weight: 700; text-decoration: none; text-align: center; padding: 15px 20px; border-radius: 10px;">View My QR Code ( Click Here )</a>
|
|
35
|
+
{{#if statusLabel}}
|
|
36
|
+
{{! Whether the QR is usable yet. Sits under the button so it is read
|
|
37
|
+
before the tap, not after. `statusColor` is inlined from the
|
|
38
|
+
context because Handlebars has no helpers registered here. }}
|
|
39
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="width: 100%;">
|
|
40
|
+
<tr>
|
|
41
|
+
<td align="center" style="padding: 14px 0 0 0;">
|
|
42
|
+
<span style="color: #7b8a95; font-size: 12px; letter-spacing: 0.4px; text-transform: uppercase; font-weight: 700;">QR Status</span>
|
|
43
|
+
<span style="display: inline-block; background-color: {{statusColor}}; color: #ffffff; font-size: 13px; font-weight: 700; padding: 5px 14px; border-radius: 999px; margin-left: 8px;">{{statusLabel}}</span>
|
|
44
|
+
</td>
|
|
35
45
|
</tr>
|
|
46
|
+
</table>
|
|
47
|
+
{{/if}}
|
|
48
|
+
<p style="margin: 12px 0 0 0; color: #7b8a95; font-size: 13px; line-height: 19px; text-align: center;">Please present the QR code at the pedestrian entrance for access.</p>
|
|
49
|
+
</td>
|
|
50
|
+
</tr>
|
|
51
|
+
|
|
52
|
+
<tr>
|
|
53
|
+
<td style="padding: 26px 28px 0 28px;">
|
|
54
|
+
<p style="margin: 0 0 10px 0; color: #052439; font-size: 12px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase;">Visitor Information</p>
|
|
36
55
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
<td style="
|
|
56
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="width: 100%; border-collapse: collapse;">
|
|
57
|
+
<tr>
|
|
58
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Name</td>
|
|
59
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{name}}</td>
|
|
60
|
+
</tr>
|
|
61
|
+
{{#if isInviteEmail}}{{#if isContractor}}
|
|
62
|
+
<tr>
|
|
63
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Company</td>
|
|
64
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{company}}</td>
|
|
65
|
+
</tr>
|
|
66
|
+
<tr>
|
|
67
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Contractor Type</td>
|
|
68
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{contractorTypeLabel}}</td>
|
|
69
|
+
</tr>
|
|
70
|
+
{{/if}}{{/if}}
|
|
71
|
+
<tr>
|
|
72
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Tenant/Resident Address</td>
|
|
73
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{address}}</td>
|
|
74
|
+
</tr>
|
|
75
|
+
<tr>
|
|
76
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Contact No.</td>
|
|
77
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{contactNumber}}</td>
|
|
78
|
+
</tr>
|
|
79
|
+
<tr>
|
|
80
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Email</td>
|
|
81
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right; word-break: break-all;">{{email}}</td>
|
|
82
|
+
</tr>
|
|
83
|
+
{{#if isInviteEmail}}
|
|
84
|
+
<tr>
|
|
85
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Vehicle Plate No.</td>
|
|
86
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{plateNumber}}</td>
|
|
87
|
+
</tr>
|
|
88
|
+
<tr>
|
|
89
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Overnight Parking</td>
|
|
90
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{overnightParking}}</td>
|
|
40
91
|
</tr>
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
<td style="
|
|
92
|
+
{{/if}}
|
|
93
|
+
<tr>
|
|
94
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Arrival Date</td>
|
|
95
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{arrivalDate}}</td>
|
|
44
96
|
</tr>
|
|
45
|
-
<tr
|
|
46
|
-
<td style="
|
|
47
|
-
<td style="
|
|
97
|
+
<tr>
|
|
98
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Arrival Time</td>
|
|
99
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{arrivalTime}}</td>
|
|
48
100
|
</tr>
|
|
101
|
+
<tr>
|
|
102
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Duration</td>
|
|
103
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{duration}}</td>
|
|
104
|
+
</tr>
|
|
105
|
+
{{#if isInviteEmail}}
|
|
106
|
+
<tr>
|
|
107
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Number of Passenger</td>
|
|
108
|
+
<td style="padding: 11px 0; border-top: 1px solid #e7ecf0; color: #052439; font-size: 14px; font-weight: 600; text-align: right;">{{numberOfPassengers}}</td>
|
|
109
|
+
</tr>
|
|
110
|
+
{{/if}}
|
|
111
|
+
{{! Stacked rather than right-aligned: a purpose can run long, and a
|
|
112
|
+
wrapped right-aligned value reads as ragged noise. }}
|
|
113
|
+
<tr>
|
|
114
|
+
<td colspan="2" style="padding: 11px 0 0 0; border-top: 1px solid #e7ecf0; color: #6b7c8a; font-size: 14px;">Purpose of Visit</td>
|
|
115
|
+
</tr>
|
|
116
|
+
<tr>
|
|
117
|
+
<td colspan="2" style="padding: 3px 0 11px 0; color: #052439; font-size: 14px; font-weight: 600; line-height: 21px;">{{purposeOfVisit}}</td>
|
|
118
|
+
</tr>
|
|
119
|
+
</table>
|
|
120
|
+
</td>
|
|
121
|
+
</tr>
|
|
122
|
+
|
|
123
|
+
{{#if hasMembers}}
|
|
124
|
+
<tr>
|
|
125
|
+
<td style="padding: 26px 28px 0 28px;">
|
|
126
|
+
<p style="margin: 0 0 12px 0; color: #052439; font-size: 12px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase;">Accompanying Members</p>
|
|
127
|
+
|
|
128
|
+
{{#each members}}
|
|
129
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="width: 100%; background-color: #f5f8fa; border: 1px solid #e7ecf0; border-radius: 10px; margin-bottom: 10px;">
|
|
130
|
+
<tr>
|
|
131
|
+
<td style="padding: 14px 16px;">
|
|
132
|
+
<p style="margin: 0 0 2px 0; color: #35a745; font-size: 11px; font-weight: 700; letter-spacing: 0.8px; text-transform: uppercase;">Member {{position}}</p>
|
|
133
|
+
<p style="margin: 0 0 8px 0; color: #052439; font-size: 16px; font-weight: 700;">{{name}}</p>
|
|
134
|
+
|
|
135
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="width: 100%; border-collapse: collapse;">
|
|
136
|
+
<tr>
|
|
137
|
+
<td style="padding: 5px 0; color: #6b7c8a; font-size: 13px;">NRIC / Passport No.</td>
|
|
138
|
+
<td style="padding: 5px 0; color: #052439; font-size: 13px; font-weight: 600; text-align: right;">{{nric}}</td>
|
|
139
|
+
</tr>
|
|
140
|
+
<tr>
|
|
141
|
+
<td style="padding: 5px 0; color: #6b7c8a; font-size: 13px;">Contact No.</td>
|
|
142
|
+
<td style="padding: 5px 0; color: #052439; font-size: 13px; font-weight: 600; text-align: right;">{{contact}}</td>
|
|
143
|
+
</tr>
|
|
144
|
+
<tr>
|
|
145
|
+
<td style="padding: 5px 0; color: #6b7c8a; font-size: 13px;">Vehicle Plate No.</td>
|
|
146
|
+
<td style="padding: 5px 0; color: #052439; font-size: 13px; font-weight: 600; text-align: right;">{{plateNumber}}</td>
|
|
147
|
+
</tr>
|
|
148
|
+
</table>
|
|
149
|
+
</td>
|
|
150
|
+
</tr>
|
|
151
|
+
</table>
|
|
152
|
+
{{/each}}
|
|
153
|
+
</td>
|
|
154
|
+
</tr>
|
|
155
|
+
{{/if}}
|
|
156
|
+
|
|
157
|
+
<tr>
|
|
158
|
+
<td style="padding: 26px 28px 28px 28px;">
|
|
159
|
+
<p style="margin: 0; padding-top: 18px; border-top: 1px solid #e7ecf0; color: #90a0ab; font-size: 12px; line-height: 18px; text-align: center;">This invitation was sent to you by your host.<br />© Seven365 Pte. Ltd.</p>
|
|
160
|
+
</td>
|
|
161
|
+
</tr>
|
|
49
162
|
|
|
50
|
-
|
|
51
|
-
<td style="text-align: left; font-weight: bold; padding: 8px;">Arrival Date</td>
|
|
52
|
-
<td style="text-align: right; padding: 8px;">{{arrivalDate}}</td>
|
|
53
|
-
</tr>
|
|
54
|
-
<tr style="border-bottom: 1px solid gray; padding: 20px;">
|
|
55
|
-
<td style="text-align: left; font-weight: bold; padding: 8px;">Arrival Time</td>
|
|
56
|
-
<td style="text-align: right; padding: 8px;">{{arrivalTime}}</td>
|
|
57
|
-
</tr>
|
|
58
|
-
<tr style="border-bottom: 1px solid gray; padding: 20px;">
|
|
59
|
-
<td style="text-align: left; font-weight: bold; padding: 8px;">Duration</td>
|
|
60
|
-
<td style="text-align: right; padding: 8px;">{{duration}}</td>
|
|
61
|
-
</tr>
|
|
62
|
-
<tr style=" padding: 20px;">
|
|
63
|
-
<td style="text-align: left; font-weight: bold; padding: 8px;">Purpose of Visit</td>
|
|
64
|
-
</tr>
|
|
65
|
-
<tr style="padding: 20px;"><td style="text-align: right; padding: 8px;">{{purposeOfVisit}}</td></tr>
|
|
66
|
-
</tbody>
|
|
67
|
-
</table>
|
|
68
|
-
</div>
|
|
69
|
-
<footer height="70" style="padding: 0; bottom: 0; left: 0; right: 0; z-index: 10; background-color: #fff;">
|
|
70
|
-
<div style="padding: 12px; max-width: 600px; margin-left: auto; margin-right: auto;">
|
|
71
|
-
<div style="text-align: center;">
|
|
72
|
-
<span style="font-size: 16px;">© 2024 powered by Seven365 Pte. Ltd. v.1</span>
|
|
73
|
-
</div>
|
|
74
|
-
</div>
|
|
75
|
-
</footer>
|
|
76
|
-
</div>
|
|
163
|
+
</table>
|
|
77
164
|
</td>
|
|
78
165
|
</tr>
|
|
79
|
-
</table>
|
|
166
|
+
</table>
|
package/dist/index.js
CHANGED
|
@@ -19980,6 +19980,33 @@ async function sendEmail({ to, subject, text: text2, html }) {
|
|
|
19980
19980
|
}
|
|
19981
19981
|
}
|
|
19982
19982
|
|
|
19983
|
+
// src/utils/visitor-email.util.ts
|
|
19984
|
+
var maskNRIC = (value) => {
|
|
19985
|
+
const nric = (value ?? "").trim();
|
|
19986
|
+
if (!nric)
|
|
19987
|
+
return "";
|
|
19988
|
+
if (nric.length <= 4)
|
|
19989
|
+
return nric;
|
|
19990
|
+
return `${"*".repeat(nric.length - 4)}${nric.slice(-4)}`;
|
|
19991
|
+
};
|
|
19992
|
+
var formatContractorType = (value) => (value ?? "").trim().split(/[-_\s]+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
|
|
19993
|
+
var VISITOR_STATUS_BADGE = {
|
|
19994
|
+
registered: { label: "Checked In", color: "#3B82F6" },
|
|
19995
|
+
invited: { label: "Invited", color: "#6B7280" },
|
|
19996
|
+
"checked-out": { label: "Checked Out", color: "#EF4444" },
|
|
19997
|
+
approved: { label: "Approved", color: "#10B981" },
|
|
19998
|
+
pending: { label: "Pending", color: "#FBBF24" }
|
|
19999
|
+
};
|
|
20000
|
+
var visitorStatusBadge = (status) => {
|
|
20001
|
+
const key = (status ?? "").trim().toLowerCase();
|
|
20002
|
+
if (!key)
|
|
20003
|
+
return { label: "", color: "#6B7280" };
|
|
20004
|
+
return VISITOR_STATUS_BADGE[key] ?? {
|
|
20005
|
+
label: key.charAt(0).toUpperCase() + key.slice(1),
|
|
20006
|
+
color: "#6B7280"
|
|
20007
|
+
};
|
|
20008
|
+
};
|
|
20009
|
+
|
|
19983
20010
|
// src/utils/visitor-status.util.ts
|
|
19984
20011
|
var PRE_CHECK_IN_STATUSES = [
|
|
19985
20012
|
"approved" /* APPROVED */,
|
|
@@ -20742,21 +20769,50 @@ function useVisitorTransactionRepo() {
|
|
|
20742
20769
|
const qrLink = `${baseUrl}/resident/invite/register/${updatedDocument?._id}`;
|
|
20743
20770
|
const logo = `${baseUrl}/images/resident/dark/seven-365.svg`;
|
|
20744
20771
|
const arrivalDate = updatedDocument?.expectedCheckIn ? (0, import_moment_timezone.default)(updatedDocument.expectedCheckIn).tz("Asia/Singapore").format("DD/MM/YYYY") : "No Arrival Date";
|
|
20772
|
+
const isLead = !updatedDocument?.leadId;
|
|
20773
|
+
const memberRows = isLead && Array.isArray(updatedDocument?.members) ? updatedDocument.members.map((member, index) => ({
|
|
20774
|
+
position: index + 1,
|
|
20775
|
+
name: member?.name?.trim() || "Unknown",
|
|
20776
|
+
nric: maskNRIC(member?.nric) || "N/A",
|
|
20777
|
+
contact: member?.contact || "N/A",
|
|
20778
|
+
plateNumber: member?.plateNumber || "N/A"
|
|
20779
|
+
})) : [];
|
|
20780
|
+
const statusBadge = visitorStatusBadge(updatedDocument?.status);
|
|
20745
20781
|
let context = {
|
|
20746
20782
|
logo,
|
|
20747
20783
|
qrLink,
|
|
20784
|
+
// Whether the QR is usable yet. Same label and colour the resident
|
|
20785
|
+
// sees in the app, so the two never disagree.
|
|
20786
|
+
statusLabel: statusBadge.label,
|
|
20787
|
+
statusColor: statusBadge.color,
|
|
20788
|
+
// `isInviteEmail` gates every row added for the resident invite. The
|
|
20789
|
+
// legacy `residentAppInvitePreRegister` sender in the API repo renders
|
|
20790
|
+
// these same templates from a different document shape and has none of
|
|
20791
|
+
// these keys -- Handlebars prints a missing key as an empty string, so
|
|
20792
|
+
// without this flag its email would grow a column of blank cells.
|
|
20793
|
+
isInviteEmail: true,
|
|
20794
|
+
isContractor: updatedDocument?.type === "contractor",
|
|
20795
|
+
company: updatedDocument?.company || "N/A",
|
|
20796
|
+
contractorTypeLabel: updatedDocument?.contractorType ? formatContractorType(updatedDocument.contractorType) : "N/A",
|
|
20748
20797
|
name: `${updatedDocument?.name}`,
|
|
20749
|
-
plateNumber: updatedDocument?.plateNumber,
|
|
20798
|
+
plateNumber: updatedDocument?.plateNumber || "N/A",
|
|
20799
|
+
overnightParking: updatedDocument?.isOvernightParking ? "Yes" : "No",
|
|
20800
|
+
numberOfPassengers: updatedDocument?.numberOfPassengers ?? 0,
|
|
20750
20801
|
nric: updatedDocument?.nric,
|
|
20751
20802
|
address: `${updatedDocument?.blockName} ${updatedDocument?.levelName} ${updatedDocument?.unitName}`,
|
|
20752
20803
|
contactNumber: updatedDocument?.contact ? updatedDocument?.contact : "N/A",
|
|
20753
20804
|
email: updatedDocument?.email ? updatedDocument?.email : "N/A",
|
|
20754
20805
|
duration: updatedDocument?.duration ? updatedDocument?.duration : "N/A",
|
|
20755
|
-
remarks: updatedDocument?.purpose ? updatedDocument?.purpose : "N/A",
|
|
20756
20806
|
arrivalDate,
|
|
20757
20807
|
arrivalTime: updatedDocument?.arrivalTime ? updatedDocument?.arrivalTime : "N/A",
|
|
20758
20808
|
hoursString: updatedDocument?.duration ? `Hour(s)` : "N/A",
|
|
20759
|
-
|
|
20809
|
+
// The invite route accepts `purpose` and never `remarks`, so reading
|
|
20810
|
+
// `remarks` first (as this did) printed "N/A" for every invite. `remarks`
|
|
20811
|
+
// stays as the fallback because the property-management approval flow does
|
|
20812
|
+
// write it.
|
|
20813
|
+
purposeOfVisit: updatedDocument?.purpose || updatedDocument?.remarks || "N/A",
|
|
20814
|
+
members: memberRows,
|
|
20815
|
+
hasMembers: memberRows.length > 0
|
|
20760
20816
|
};
|
|
20761
20817
|
let handlebar = "approve-walk-in";
|
|
20762
20818
|
if (updatedDocument?.isOvernightParking != null || updatedDocument?.plateNumber) {
|