Task #349: Executive Meetings PDF improvements

- Schema: add `font_color` (hex, default #000000) and `logo_object_path`
  to `executive_meeting_font_settings`. Pushed via drizzle-kit.

- PDF renderer:
  - Add `fontColor` to PdfFontPrefs (body cells only; header chrome
    and logo intentionally ignore it to preserve branding).
  - Add `rowColor` to PdfMeeting and a ROW_COLOR_FILL palette kept in
    lockstep with the on-screen swatches; deliberately stop painting
    the legacy `isHighlighted` overlay so the archived PDF reflects
    editorial state instead of the viewer's transient cursor.
  - Add optional `logo: Buffer`. Header now reserves a left-anchored
    logo box and centers the title in the remaining width; bad image
    bytes log + fall back to the no-logo layout instead of crashing.

- API route:
  - Extend fontSettingsSchema with strict #RRGGBB regex and
    /^/objects/<id>$/ regex for logoObjectPath.
  - resolveFontPrefsForUser now returns { font, logoObjectPath }.
  - loadLogoBytes downloads the brand asset via ObjectStorageService.
  - Logo only writable on the global-scope row.
  - PDF labels switched to "قائمة بأسماء حضور الاجتماعات" /
    "Meeting Attendance List" per the user's printed sample.

- Frontend (executive-meetings.tsx):
  - FontPrefs gains fontColor; FontSettingsResponse.global gains
    logoObjectPath; DEFAULT_FONT and effectiveFont updated.
  - buildFontStyle applies fontColor to on-screen rows.
  - FontSettingsSection: native color picker + hex text input;
    logo upload (PNG/JPEG) via @workspace/object-storage-web's
    useUpload, visible only at the global scope for admins.

- Locales: AR/EN keys for fontColor + logo.{label,upload,replace,
  remove,uploading,uploadFailed,globalOnly}.

- Tests: existing font-settings roundtrip extended with fontColor;
  new test rejects malformed fontColor and non-/objects logo paths.

Type-check clean for api-server and tx-os; new font-settings tests
pass. Other test failures in the suite pre-date this change.
This commit is contained in:
riyadhafraa
2026-05-03 14:34:29 +00:00
parent 9fdabc4794
commit 57e8297464
20 changed files with 26597 additions and 28 deletions
+10
View File
@@ -274,6 +274,16 @@ export const executiveMeetingFontSettingsTable = pgTable(
fontSize: integer("font_size").notNull().default(14),
fontWeight: varchar("font_weight", { length: 16 }).notNull().default("regular"),
alignment: varchar("alignment", { length: 16 }).notNull().default("start"),
// Hex color (#RRGGBB) applied to body cell text in both the on-screen
// schedule and the generated PDF. Default "#000000" preserves the
// historical black-text appearance for rows created before this
// column existed. Validated app-side by the regex in
// `fontSettingsSchema`.
fontColor: varchar("font_color", { length: 16 }).notNull().default("#000000"),
// Object-storage path (`/objects/<id>`) of the brand logo embedded
// in the top-left of the generated PDF header. NULL = no logo. Only
// meaningful on the global-scope row (the per-user row ignores it).
logoObjectPath: text("logo_object_path"),
updatedAt: timestamp("updated_at", { withTimezone: true })
.notNull()
.defaultNow()