@acms-subir/core 0.3.52 → 0.3.54
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/CHANGELOG.md +29 -0
- package/cli/migrations.generated.mjs +18 -1
- package/docs/calendar.md +20 -2
- package/docs/mobile.md +1 -1
- package/docs/server.md +61 -1
- package/integration.mjs +11 -5
- package/mobile-template/recipes/events/files/components/RsvpPanel.tsx +2 -2
- package/mobile-template/recipes/rsvp/files/components/RsvpPanel.tsx +2 -2
- package/package.json +1 -1
- package/src/components/ThemeSections.astro +2 -2
- package/src/components/editor/PostEditor.tsx +2 -0
- package/src/components/editor/event/EventSheet.tsx +6 -2
- package/src/components/editor/event/RegistrationCard.tsx +3 -3
- package/src/components/editor/event/RegistrationFormEditor.tsx +6 -3
- package/src/components/forms/Canvas.tsx +31 -19
- package/src/components/forms/FormBuildPage.tsx +12 -6
- package/src/components/forms/FormBuilder.tsx +60 -11
- package/src/components/forms/Inspector.tsx +116 -8
- package/src/components/forms/TypeIcon.tsx +1 -0
- package/src/components/forms/meta.ts +71 -9
- package/src/lib/api.ts +3 -0
- package/src/lib/backup/content.ts +4 -2
- package/src/lib/calendar/api.ts +3 -1
- package/src/lib/calendar/host-requests.ts +247 -0
- package/src/lib/calendar/member-form.ts +17 -11
- package/src/lib/calendar/member-words.ts +473 -0
- package/src/lib/calendar/members-config.ts +2 -2
- package/src/lib/calendar/moves.ts +81 -33
- package/src/lib/calendar/request-migration.ts +17 -0
- package/src/lib/calendar/request-store.ts +104 -0
- package/src/lib/calendar/requests.ts +24 -24
- package/src/lib/dynamicBlocks.ts +4 -2
- package/src/lib/email/service.ts +12 -2
- package/src/lib/email/templates.ts +12 -2
- package/src/lib/forms/fields.ts +14 -9
- package/src/lib/forms/localize.ts +68 -0
- package/src/lib/forms/render.ts +8 -2
- package/src/lib/forms/schema.ts +31 -2
- package/src/lib/forms/service.ts +9 -1
- package/src/lib/forms/validate.ts +16 -4
- package/src/lib/forms/words.ts +32 -0
- package/src/lib/mobile/forms.ts +45 -13
- package/src/lib/mobile/openapi.ts +3 -3
- package/src/lib/mobile/rsvp.ts +4 -2
- package/src/lib/mobile/schemas.ts +3 -1
- package/src/lib/repo/migrations.ts +4 -0
- package/src/lib/repo/sql.ts +7 -0
- package/src/lib/repo/types.ts +6 -1
- package/src/lib/schema.ts +47 -0
- package/src/pages/[...slug].astro +1 -1
- package/src/pages/admin/calendar/events/index.astro +82 -6
- package/src/pages/admin/forms/[id].astro +6 -0
- package/src/pages/admin/index.astro +6 -2
- package/src/pages/blog/[slug].astro +1 -1
- package/src/pages/events/[slug].astro +9 -3
- package/src/pages/forms/[id].astro +22 -4
- package/src/pages/index.astro +1 -1
- package/src/pages/members/_EventForm.astro +33 -27
- package/src/pages/members/_Layout.astro +25 -5
- package/src/pages/members/_http.ts +29 -6
- package/src/pages/members/events/[id].astro +21 -20
- package/src/pages/members/events/index.astro +295 -101
- package/src/pages/members/events/new.astro +11 -10
- package/src/server/index.ts +53 -0
- package/src/styles/forms.css +8 -0
- package/src/virtual.d.ts +1 -1
|
@@ -6,16 +6,17 @@ import { currentUser } from '../../../server';
|
|
|
6
6
|
import { readForm } from '../../../lib/forms/http';
|
|
7
7
|
import { MEMBERS, memberEventsPath, submitEventRequest } from '../../../lib/calendar/requests';
|
|
8
8
|
import { blankEventForm, eventRequestInput, memberEventFields, readEventForm } from '../../../lib/calendar/member-form';
|
|
9
|
-
import { failure, keepPrivate, notFound, redirectTo, signInRedirect } from '../_http';
|
|
9
|
+
import { failure, keepPrivate, memberLanguage, notFound, redirectTo, signInRedirect } from '../_http';
|
|
10
10
|
|
|
11
11
|
// "Request an event": a draft the member hosts, waiting for the team's
|
|
12
12
|
// approval (submitEventRequest checks who may ask and what they sent).
|
|
13
13
|
if (!MEMBERS.enabled) return notFound();
|
|
14
14
|
const user = await currentUser(Astro);
|
|
15
|
-
if (!user) return signInRedirect(Astro.url);
|
|
15
|
+
if (!user) return signInRedirect(Astro.url, Astro.locals);
|
|
16
16
|
keepPrivate(Astro.response.headers);
|
|
17
17
|
const repo = await getRepo(Astro.locals);
|
|
18
|
-
const
|
|
18
|
+
const { w, lang, here } = memberLanguage(Astro, await repo.getSettings());
|
|
19
|
+
const home = here(memberEventsPath());
|
|
19
20
|
const fields = memberEventFields();
|
|
20
21
|
const calendars = (await repo.listCalendars()).filter((c) => c.kind === 'native' && c.visibility === 'public');
|
|
21
22
|
|
|
@@ -28,7 +29,7 @@ if (Astro.request.method === 'POST') {
|
|
|
28
29
|
await submitEventRequest(repo, user, eventRequestInput(values), { url: Astro.url, locals: Astro.locals });
|
|
29
30
|
return redirectTo(`${home}?sent=1`);
|
|
30
31
|
} catch (err) {
|
|
31
|
-
const f = failure(err);
|
|
32
|
+
const f = failure(err, w, lang);
|
|
32
33
|
error = f.message;
|
|
33
34
|
Astro.response.status = f.status;
|
|
34
35
|
}
|
|
@@ -36,13 +37,13 @@ if (Astro.request.method === 'POST') {
|
|
|
36
37
|
const canRequest = user.can('events.request');
|
|
37
38
|
---
|
|
38
39
|
|
|
39
|
-
<Layout title=
|
|
40
|
+
<Layout title={w.newTitle} user={user} w={w}>
|
|
40
41
|
<div>
|
|
41
|
-
<a class="pc-mem-back" href={home}
|
|
42
|
-
<div class="pc-mem-head"><h1>
|
|
43
|
-
<p class="pc-mem-lede">
|
|
42
|
+
<a class="pc-mem-back" href={home}>{w.back}</a>
|
|
43
|
+
<div class="pc-mem-head"><h1>{w.newTitle}</h1></div>
|
|
44
|
+
<p class="pc-mem-lede">{w.newLede}</p>
|
|
44
45
|
</div>
|
|
45
46
|
{canRequest
|
|
46
|
-
? <EventForm values={values} calendars={calendars} fields={fields} op="submit" submitLabel=
|
|
47
|
-
: <p class="pc-bk-error" role="alert">
|
|
47
|
+
? <EventForm values={values} calendars={calendars} fields={fields} op="submit" submitLabel={w.submit} error={error} w={w} lang={lang} />
|
|
48
|
+
: <p class="pc-bk-error" role="alert">{w.noRequestRole}</p>}
|
|
48
49
|
</Layout>
|
package/src/server/index.ts
CHANGED
|
@@ -300,3 +300,56 @@ export async function declineEventRequest(repo: Repo, who: Who, eventId: string,
|
|
|
300
300
|
export async function setHostedOccurrence(repo: Repo, who: Who, eventId: string, occurrenceKey: string, cancelled: boolean, context: WriteContext): Promise<CalEvent> {
|
|
301
301
|
return (await requests()).setHostedOccurrence(internal(repo), who, eventId, occurrenceKey, cancelled, context);
|
|
302
302
|
}
|
|
303
|
+
|
|
304
|
+
// ---- hosts moving dates ------------------------------------------------------
|
|
305
|
+
// A host moves one date of an event they host (no permission beyond being in
|
|
306
|
+
// hostIds). acms({ members: { hostMoves } }) decides how: 'direct' (default)
|
|
307
|
+
// moves it at once while its rooms are free (409 room-taken otherwise, and
|
|
308
|
+
// the same move can then be sent with requestDateMove); 'approve' turns every
|
|
309
|
+
// host move into a request. Requests are RequestRecord rows (kind 'move')
|
|
310
|
+
// that staff who can publish approve or decline; both sides are emailed.
|
|
311
|
+
|
|
312
|
+
const hostRequests = () => import('../lib/calendar/host-requests');
|
|
313
|
+
export type { HostMoveResult, MoveRequestData } from '../lib/calendar/host-requests';
|
|
314
|
+
export type { RequestRecord } from '../lib/schema';
|
|
315
|
+
|
|
316
|
+
/** A host moves one date: `{ moved }` at once, or `{ request }` when moves need approval. Errors as moveOccurrence's, plus `code` room-not-allowed (a room the event doesn't use and nobody may request). */
|
|
317
|
+
export async function moveHostedDate(repo: Repo, who: Who, eventId: string, occurrenceKey: string, input: import('../lib/calendar/moves').MoveInput, context: WriteContext): Promise<import('../lib/calendar/host-requests').HostMoveResult> {
|
|
318
|
+
return (await hostRequests()).moveHostedDate(internal(repo), who, eventId, occurrenceKey, input, context);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/** A host puts a date they moved back where the series has it: at once, or as a request. */
|
|
322
|
+
export async function moveHostedDateBack(repo: Repo, who: Who, eventId: string, occurrenceKey: string, context: WriteContext): Promise<import('../lib/calendar/host-requests').HostMoveResult> {
|
|
323
|
+
return (await hostRequests()).moveHostedDateBack(internal(repo), who, eventId, occurrenceKey, context);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* A host asks staff to move one date (`input`), or to move it back (null),
|
|
328
|
+
* with an optional `message` for staff. Checked like the move, except that a
|
|
329
|
+
* taken room is allowed: staff decide. Asking again about the same date
|
|
330
|
+
* replaces the waiting request. Staff are emailed.
|
|
331
|
+
*/
|
|
332
|
+
export async function requestDateMove(repo: Repo, who: Who, eventId: string, occurrenceKey: string, input: import('../lib/calendar/moves').MoveInput | null, message: string, context: WriteContext): Promise<import('../lib/schema').RequestRecord> {
|
|
333
|
+
return (await hostRequests()).requestDateMove(internal(repo), who, eventId, occurrenceKey, input, message, context);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/** A host's own date requests (waiting, approved, declined and withdrawn), newest first. */
|
|
337
|
+
export async function listMyDateRequests(repo: Repo, who: Who, eventId?: string): Promise<import('../lib/schema').RequestRecord[]> {
|
|
338
|
+
if (!who) return [];
|
|
339
|
+
return (await hostRequests()).myDateRequests(internal(repo), who.id, eventId);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** A host withdraws a waiting date request of theirs. */
|
|
343
|
+
export async function withdrawDateRequest(repo: Repo, who: Who, requestId: string): Promise<void> {
|
|
344
|
+
return (await hostRequests()).withdrawDateRequest(internal(repo), who, requestId);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/** Staff ("Publish content"): approve a host's date move. It runs as them (room clashes come back as warnings) and is recorded as the host's. Pass `seen`, the request's `updatedAt` you showed. */
|
|
348
|
+
export async function approveDateRequest(repo: Repo, who: Who, requestId: string, context: WriteContext, seen?: number): Promise<{ request: import('../lib/schema').RequestRecord; moved: import('../lib/calendar/moves').MoveResult }> {
|
|
349
|
+
return (await hostRequests()).approveDateRequest(internal(repo), who, requestId, context, seen);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** Staff: decline a host's date request, with a note the host reads. */
|
|
353
|
+
export async function declineDateRequest(repo: Repo, who: Who, requestId: string, reply: string, context: WriteContext, seen?: number): Promise<import('../lib/schema').RequestRecord> {
|
|
354
|
+
return (await hostRequests()).declineDateRequest(internal(repo), who, requestId, reply, context, seen);
|
|
355
|
+
}
|
package/src/styles/forms.css
CHANGED
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
.fb.is-preview .fb-canvas { border: 0; }
|
|
82
82
|
.fb-wide .fb-canvas:has(> .fb-float) { padding-top: 48px; }
|
|
83
83
|
.fb-float { position: absolute; top: 8px; right: 10px; z-index: 3; display: flex; gap: 2px; padding: 2px; border-radius: 10px; background: color-mix(in srgb, var(--panel-2) 85%, transparent); }
|
|
84
|
+
.fb-float-l { right: auto; left: 10px; }
|
|
84
85
|
.fb-paper {
|
|
85
86
|
/* the public form's tokens, mapped onto the admin palette */
|
|
86
87
|
--ink: var(--text); --line-2: var(--line-strong); --btn: var(--text); --btn-ink: var(--bg); --accent-text: var(--accent-deep);
|
|
@@ -195,6 +196,13 @@
|
|
|
195
196
|
.fb-choice.dragging input { box-shadow: var(--shadow-pop); }
|
|
196
197
|
.fb-choice input { min-height: 34px; }
|
|
197
198
|
.fb-choice-add { margin: 2px 0 0; font-size: 12px; color: var(--muted); }
|
|
199
|
+
/* another language: the main language's words above each box, choices side by side */
|
|
200
|
+
.fb-src { display: block; padding: 6px 9px; border-radius: var(--r-sm); background: var(--panel-2); color: var(--text-2); font-size: 12.5px; line-height: 1.45; white-space: pre-line; overflow-wrap: anywhere; max-height: 7.5em; overflow: auto; }
|
|
201
|
+
.fb-src > span { display: block; font-size: 10.5px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); margin-bottom: 1px; }
|
|
202
|
+
.fb-tr-choices { display: grid; gap: 6px; }
|
|
203
|
+
.fb-tr-choice { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); gap: 8px; align-items: center; }
|
|
204
|
+
.fb-tr-choice > span { font-size: 12.5px; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
205
|
+
.fb-tr-choice input { min-height: 34px; }
|
|
198
206
|
|
|
199
207
|
/* menus */
|
|
200
208
|
.fb-more, .fb-q-more { position: relative; flex: none; }
|
package/src/virtual.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ declare module 'virtual:acms-config' {
|
|
|
22
22
|
// resolved by integration.mjs (lib/roles.ts and lib/permissions/catalog.ts read them)
|
|
23
23
|
roles?: { key: string; label: string; summary: string; admin: boolean; home: string }[];
|
|
24
24
|
permissions?: { key: string; label: string; description: string; defaults: string[]; sensitive: boolean }[];
|
|
25
|
-
members?: { enabled: boolean; base: string; notify: string[] };
|
|
25
|
+
members?: { enabled: boolean; base: string; notify: string[]; hostMoves?: 'direct' | 'approve' };
|
|
26
26
|
announcements?: { enabled: boolean; base: string; pages: boolean; topics: Partial<Record<'event' | 'registration' | 'help' | 'info', string>> };
|
|
27
27
|
// set in astro:config:setup (lib/origin-check.ts): off only when the site turned security.checkOrigin off
|
|
28
28
|
originCheck?: { enabled: boolean; signedRoutes: string[] };
|