Commit Graph

5 Commits

Author SHA1 Message Date
Darko Gjorgjijoski
e6eeacb6d4 feat(modules): company-context module surfaces and schema-driven settings
Adds the read-only company "Active Modules" index page (lists every
instance-activated module with a Settings shortcut) and the schema-driven
settings framework (generic BaseSchemaForm.vue renderer + per-company
persistence in CompanySetting). Bundled because they share the same
routes/api.php edit and the index page's Settings button targets the
settings page.

Backend:

- CompanyModulesController::index() returns every Module::enabled = true row
  with a kebab-case slug (via Str::kebab()) and a has_settings flag computed
  from \InvoiceShelf\Modules\Registry::settingsFor(). nwidart stores module
  names in PascalCase ("HelloWorld") but URLs and registry keys use kebab
  ("hello-world") — the controller normalizes so module authors can call
  Registry::registerSettings('hello-world') naturally without thinking
  about the storage format.

- ModuleSettingsController::show(\$slug) returns the registered Schema +
  per-company values from CompanySetting (defaults flow through when nothing
  has been saved yet). update(\$slug) builds Laravel validator rules from
  the Schema's per-field rules arrays — with type-rule fallbacks for
  switch -> boolean, number -> numeric, multiselect -> array — silently
  drops unknown keys, and persists via CompanySetting::setSettings() under
  the module.{slug}.{key} prefix. Activation is instance-global, but
  settings are per-company: two companies on the same instance can
  configure the same activated module differently.

- routes/api.php mounts GET /api/v1/company-modules at the root of the
  company API group and GET/PUT /api/v1/modules/{slug}/settings inside the
  existing modules prefix.

Frontend:

- BaseSchemaForm.vue is the central new component — a generic schema-driven
  form renderer that maps schema fields to BaseInput / BaseTextarea /
  BaseSwitch / BaseMultiselect by type, and builds Vuelidate rules
  dynamically from each field's rules array (supports required, email, url,
  numeric, min:N, max:N). New fields are added by extending the type ->
  component map.

- CompanyModulesIndexView.vue fetches /company-modules and renders a card
  grid (with empty/loading states); CompanyModuleCard.vue is the per-row
  component with the Settings button. ModuleSettingsView.vue fetches
  /modules/{slug}/settings, hands {schema, values} to BaseSchemaForm, and
  posts back on submit.

- Company-context routes.ts is rebuilt after the previous commit relocated
  the marketplace browser away. It now declares modules.index +
  modules.settings, both gated by manage-module ability.

- New api/services/{companyModules,moduleSettings}.service.ts thin clients.

- lang/en.json adds modules.index.{description,empty_title,empty_description},
  modules.settings.{title,open,saved,not_found,none}, and
  modules.sidebar.section_title. The sidebar key is added here even though
  the dynamic sidebar rendering lands in the next commit — keeping all i18n
  additions in one file edit avoids hunk-splitting lang/en.json.
2026-04-09 00:29:36 +02:00
Darko Gjorgjijoski
84725b2dfa feat(modules): relocate marketplace browser to super-admin context
The module marketplace browser UI (ModuleIndexView, ModuleDetailView,
ModuleCard, the four-step installer store) was filed under
features/company/modules/ only by historical accident — it's authorized via
the manage modules ability (super-admin-only) and conceptually belongs in the
admin context, not the company context.

- Move features/company/modules/{store.ts, views/ModuleIndexView.vue,
  views/ModuleDetailView.vue, components/ModuleCard.vue} to
  features/admin/modules/.
- Update hardcoded /admin/modules/... paths in the moved files to
  /admin/administration/modules/... so the breadcrumbs and ModuleCard
  navigation target the new admin-context routes.
- Tighten the four-step installer's silent catch {} blocks in the moved
  store.ts: errors were being swallowed, now they dispatch through the
  global notification store instead.
- New features/admin/modules/routes.ts declares admin.modules.index +
  admin.modules.view as children of /admin/administration with
  meta.isSuperAdmin: true.
- features/admin/{index,routes}.ts re-export and mount the relocated routes.
- config/invoiceshelf.php gains a new AdminModules entry in admin_menu
  pointing at /admin/administration/modules with super_admin_only: true.
- The dev-gated navigation.modules entry in main_menu is replaced (not
  deleted) with a non-gated entry pointing at the new company-context
  Active Modules index page that lands in the next commit. The
  ability is set to manage modules so non-owners can't see it.

The new company-context Active Modules index, schema-driven settings page,
and dynamic sidebar group are introduced in subsequent commits.
2026-04-09 00:28:59 +02:00
Darko Gjorgjijoski
999ff3e977 Auto-update invoice due date when invoice date changes
Port of master's 241ec092 (Feat: Automatically set due date when invoice date is changed). The original commit was a JavaScript Options-API watcher in the deleted v1 InvoiceCreate.vue; v3.0's equivalent is a Composition-API TypeScript view at resources/scripts/features/company/invoices/views/InvoiceCreateView.vue, so this is a re-implementation rather than a cherry-pick.

Behaviour: if the company setting invoice_set_due_date_automatically is 'YES', a watcher on invoiceStore.newInvoice.invoice_date recomputes the due date as invoice_date + invoice_due_date_days whenever the invoice date changes. A second watcher on due_date tracks whether the user has manually edited it; if the manual value is still valid (>= the new invoice date) it is left alone, otherwise the auto value takes over. An isAutoUpdatingDueDate guard avoids a feedback loop when the watcher writes back to the store.

Uses moment for the date math, matching the original master commit and several other v3.0 features (reports, CreateCustomFields) that already import moment. companyStore is newly imported in this view to read selectedCompanySettings.
2026-04-07 17:33:03 +02:00
Darko Gjorgjijoski
6fdf10b2b1 Rebuild auth pages on the project design system
Rewrites resources/scripts/layouts/AuthLayout.vue from scratch using only the @theme tokens defined in themes.css and registered via @theme inline in invoiceshelf.css. The new layout is a centered card on the existing bg-glass-gradient utility, using the same visual vocabulary as BaseCard (bg-surface, rounded-xl, border-line-default, shadow-sm) so the auth pages read as a smaller, simpler version of the admin's existing card pattern. Both light and dark mode work automatically because every color references a theme token rather than a hardcoded hex/rgb.

Drops the previous attempt's hardcoded #0a0e1a / #fbbf24 / #f5efe5 palette, the imported Google Fonts (Fraunces / Manrope / JetBrains Mono — replaced with the project default Poppins via font-base), the local --ink / --brass / --cream CSS variables that ignored [data-theme=dark], and the :deep() overrides that forced BaseInput / BaseButton into a custom underline style. The form components now render in the auth card identically to how they render anywhere else in the admin — same components, same theme tokens, no overrides.

Removes four legacy SVG decorations from the original two-panel design: LoginPlanetCrater, LoginBackground, LoginBackgroundOverlay, LoginBottomVector. The page now has no decorative imagery — the bg-glass-gradient utility carries the visual mood.

Adds w-full justify-center to the four auth-form submit buttons (LoginView, ForgotPasswordView, ResetPasswordView, RegisterWithInvitationView) so they fill the auth card width with their labels centered. Done at the call site rather than via :deep() so BaseButton stays untouched and the rest of the admin keeps its inline button style. Route-aware heading/subheading copy is preserved for all four auth views, and the four window.* admin customization hooks (login_page_logo, login_page_heading, login_page_description, copyright_text) still work.
2026-04-07 14:18:34 +02:00
Darko Gjorgjijoski
71388ec6a5 Rename resources/scripts-v2 to resources/scripts and drop @v2 alias
Now that the legacy v1 frontend (commit 064bdf53) is gone, the v2 directory is the only frontend and the v2 suffix is just noise. Renames resources/scripts-v2 to resources/scripts via git mv (so git records the move as renames, preserving blame and log --follow), then bulk-rewrites the 152 files that imported via @v2/... to use @/scripts/... instead. The existing @ alias (resources/) covers the new path with no extra config needed.

Drops the now-unused @v2 alias from vite.config.js and points the laravel-vite-plugin entry at resources/scripts/main.ts. Updates the only blade reference (resources/views/app.blade.php) to match. The package.json test script (eslint ./resources/scripts) automatically targets the right place after the rename without any edit.

Verified: npm run build exits clean and the Vite warning lines now reference resources/scripts/plugins/i18n.ts, confirming every import resolved through the new path. git log --follow on any moved file walks back through its scripts-v2 history.
2026-04-07 12:50:16 +02:00