feat: wire GHL webhook to Resend email templates
- Replace raw Resend text emails with sendMail using Resend templates - automated-user-registration template: firstName, tempPassword, verifyUrl, loginUrl - license-key-delivery template: firstName, license_key - Remove requestPasswordReset call (temp password is the one-time credential; verification link handles email confirmation) - Add .catch() to Better Auth email callbacks to prevent unhandled rejections from missing templates crashing the server
This commit is contained in:
@@ -58,16 +58,16 @@ State variables declared with `$state('')` are set once on component mount. To k
|
||||
|
||||
```svelte
|
||||
<script lang="ts">
|
||||
let { record = {} as Record<string, unknown> } = $props();
|
||||
let { record = {} as Record<string, unknown> } = $props();
|
||||
|
||||
let name = $state('');
|
||||
let freq = $state('');
|
||||
let name = $state('');
|
||||
let freq = $state('');
|
||||
|
||||
// Sync local state when prop changes
|
||||
$effect(() => {
|
||||
name = String(record.name ?? '');
|
||||
freq = String(record.solfeggioFrequencyId ?? '');
|
||||
});
|
||||
// Sync local state when prop changes
|
||||
$effect(() => {
|
||||
name = String(record.name ?? '');
|
||||
freq = String(record.solfeggioFrequencyId ?? '');
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
@@ -164,17 +164,18 @@ For every admin route, write BOTH:
|
||||
|
||||
These methods are available on `page` from `vitest/browser`:
|
||||
|
||||
| Method | Works? | Example |
|
||||
|--------|--------|---------|
|
||||
| `getByRole` | ✅ | `page.getByRole('textbox', { name: 'Name' })` |
|
||||
| `getByText` | ✅ | `page.getByText('Content')` |
|
||||
| `getByPlaceholder` | ✅ | `page.getByPlaceholder('Email Address')` |
|
||||
| `getByAltText` | ✅ | `page.getByAltText('Sign In with Google')` |
|
||||
| `getByTestId` | ✅ | `page.getByTestId('tiptap-mock')` |
|
||||
| `getByLabel` | ❌ | Not available in this version |
|
||||
| `getByDisplayValue` | ❌ | Not available in this version |
|
||||
| Method | Works? | Example |
|
||||
| ------------------- | ------ | --------------------------------------------- |
|
||||
| `getByRole` | ✅ | `page.getByRole('textbox', { name: 'Name' })` |
|
||||
| `getByText` | ✅ | `page.getByText('Content')` |
|
||||
| `getByPlaceholder` | ✅ | `page.getByPlaceholder('Email Address')` |
|
||||
| `getByAltText` | ✅ | `page.getByAltText('Sign In with Google')` |
|
||||
| `getByTestId` | ✅ | `page.getByTestId('tiptap-mock')` |
|
||||
| `getByLabel` | ❌ | Not available in this version |
|
||||
| `getByDisplayValue` | ❌ | Not available in this version |
|
||||
|
||||
For label-identified elements, use `getByRole` with `name` option:
|
||||
|
||||
- Text inputs → `getByRole('textbox', { name: /^Name$/ })`
|
||||
- Selects → `getByRole('combobox', { name: /^Frequency$/ })`
|
||||
- Buttons → `getByRole('button', { name: 'Save' })`
|
||||
@@ -186,7 +187,9 @@ For label-identified elements, use `getByRole` with `name` option:
|
||||
Since `bind:value` on selects doesn't work with `$effect`-driven state, and we use `selected` on `<option>` instead, you can check the select's value directly:
|
||||
|
||||
```ts
|
||||
const el = await page.getByRole('combobox', { name: /^Frequency$/ }).element() as HTMLSelectElement;
|
||||
const el = (await page
|
||||
.getByRole('combobox', { name: /^Frequency$/ })
|
||||
.element()) as HTMLSelectElement;
|
||||
expect(el.value).toBe('2');
|
||||
```
|
||||
|
||||
@@ -251,6 +254,7 @@ Imports of the mocked module must come AFTER `vi.mock()` calls.
|
||||
### Per-route form components
|
||||
|
||||
Each admin route under `admin/[model]/` has its own form component (e.g. `ProclamationForm.svelte`). These components:
|
||||
|
||||
- Receive `record`, `fieldErrors`, `formError`, `relationOptionsData`, and model-specific extras (e.g. `categories`, `isSuper`) as props.
|
||||
- Use `$state` + `$effect` for field values (see "Svelte 5 Runes Gotchas" above).
|
||||
- Use `selected` on `<option>` for selects.
|
||||
|
||||
Reference in New Issue
Block a user