@stacksjs/defaults 0.70.206 → 0.70.208
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/TODO.md +21 -0
- package/ai/AGENTS.md +79 -0
- package/ai/README.md +45 -0
- package/ai/claude/launch.json +12 -0
- package/ai/skills/stacks-actions/SKILL.md +128 -0
- package/ai/skills/stacks-ai/SKILL.md +276 -0
- package/ai/skills/stacks-alias/SKILL.md +94 -0
- package/ai/skills/stacks-analytics/SKILL.md +91 -0
- package/ai/skills/stacks-api/SKILL.md +738 -0
- package/ai/skills/stacks-arrays/SKILL.md +277 -0
- package/ai/skills/stacks-auth/SKILL.md +422 -0
- package/ai/skills/stacks-auto-imports/SKILL.md +138 -0
- package/ai/skills/stacks-brandkit/SKILL.md +811 -0
- package/ai/skills/stacks-browse/SKILL.md +127 -0
- package/ai/skills/stacks-browse/scripts/browse.ts +492 -0
- package/ai/skills/stacks-browser/SKILL.md +145 -0
- package/ai/skills/stacks-buddy/SKILL.md +676 -0
- package/ai/skills/stacks-build/SKILL.md +163 -0
- package/ai/skills/stacks-cache/SKILL.md +125 -0
- package/ai/skills/stacks-calendar/SKILL.md +113 -0
- package/ai/skills/stacks-chat/SKILL.md +371 -0
- package/ai/skills/stacks-cli/SKILL.md +112 -0
- package/ai/skills/stacks-cloud/SKILL.md +192 -0
- package/ai/skills/stacks-cms/SKILL.md +217 -0
- package/ai/skills/stacks-collections/SKILL.md +82 -0
- package/ai/skills/stacks-commerce/SKILL.md +114 -0
- package/ai/skills/stacks-composables/SKILL.md +161 -0
- package/ai/skills/stacks-config/SKILL.md +144 -0
- package/ai/skills/stacks-configuration/SKILL.md +154 -0
- package/ai/skills/stacks-cron/SKILL.md +123 -0
- package/ai/skills/stacks-crosswind/SKILL.md +190 -0
- package/ai/skills/stacks-dashboard/SKILL.md +173 -0
- package/ai/skills/stacks-database/SKILL.md +286 -0
- package/ai/skills/stacks-datetime/SKILL.md +269 -0
- package/ai/skills/stacks-dependencies/SKILL.md +111 -0
- package/ai/skills/stacks-deploy/SKILL.md +102 -0
- package/ai/skills/stacks-design-brutalist/SKILL.md +110 -0
- package/ai/skills/stacks-design-minimalist/SKILL.md +115 -0
- package/ai/skills/stacks-design-output/SKILL.md +55 -0
- package/ai/skills/stacks-design-soft/SKILL.md +156 -0
- package/ai/skills/stacks-design-taste/SKILL.md +1012 -0
- package/ai/skills/stacks-design-taste-codex/SKILL.md +294 -0
- package/ai/skills/stacks-desktop/SKILL.md +78 -0
- package/ai/skills/stacks-development/SKILL.md +298 -0
- package/ai/skills/stacks-dns/SKILL.md +149 -0
- package/ai/skills/stacks-docs/SKILL.md +109 -0
- package/ai/skills/stacks-email/SKILL.md +236 -0
- package/ai/skills/stacks-enums/SKILL.md +100 -0
- package/ai/skills/stacks-env/SKILL.md +181 -0
- package/ai/skills/stacks-error-handling/SKILL.md +137 -0
- package/ai/skills/stacks-events/SKILL.md +228 -0
- package/ai/skills/stacks-faker/SKILL.md +158 -0
- package/ai/skills/stacks-git/SKILL.md +158 -0
- package/ai/skills/stacks-guard/SKILL.md +98 -0
- package/ai/skills/stacks-health/SKILL.md +75 -0
- package/ai/skills/stacks-http/SKILL.md +316 -0
- package/ai/skills/stacks-i18n/SKILL.md +198 -0
- package/ai/skills/stacks-image-to-code/SKILL.md +629 -0
- package/ai/skills/stacks-imagegen-mobile/SKILL.md +1474 -0
- package/ai/skills/stacks-imagegen-web/SKILL.md +998 -0
- package/ai/skills/stacks-investigate/SKILL.md +119 -0
- package/ai/skills/stacks-jobs/SKILL.md +136 -0
- package/ai/skills/stacks-lint/SKILL.md +184 -0
- package/ai/skills/stacks-listeners/SKILL.md +99 -0
- package/ai/skills/stacks-logging/SKILL.md +78 -0
- package/ai/skills/stacks-mail/SKILL.md +120 -0
- package/ai/skills/stacks-middleware/SKILL.md +249 -0
- package/ai/skills/stacks-migrations/SKILL.md +105 -0
- package/ai/skills/stacks-models/SKILL.md +267 -0
- package/ai/skills/stacks-new-feature/SKILL.md +206 -0
- package/ai/skills/stacks-notifications/SKILL.md +210 -0
- package/ai/skills/stacks-objects/SKILL.md +205 -0
- package/ai/skills/stacks-office-hours/SKILL.md +134 -0
- package/ai/skills/stacks-orm/SKILL.md +342 -0
- package/ai/skills/stacks-path/SKILL.md +118 -0
- package/ai/skills/stacks-payments/SKILL.md +373 -0
- package/ai/skills/stacks-plan-review/SKILL.md +152 -0
- package/ai/skills/stacks-plugins/SKILL.md +149 -0
- package/ai/skills/stacks-push/SKILL.md +376 -0
- package/ai/skills/stacks-query-builder/SKILL.md +128 -0
- package/ai/skills/stacks-queue/SKILL.md +559 -0
- package/ai/skills/stacks-realtime/SKILL.md +442 -0
- package/ai/skills/stacks-redesign/SKILL.md +182 -0
- package/ai/skills/stacks-registry/SKILL.md +58 -0
- package/ai/skills/stacks-repl/SKILL.md +80 -0
- package/ai/skills/stacks-retro/SKILL.md +122 -0
- package/ai/skills/stacks-review/SKILL.md +135 -0
- package/ai/skills/stacks-router/SKILL.md +231 -0
- package/ai/skills/stacks-routes/SKILL.md +105 -0
- package/ai/skills/stacks-scaffolding/SKILL.md +162 -0
- package/ai/skills/stacks-scheduler/SKILL.md +363 -0
- package/ai/skills/stacks-search-engine/SKILL.md +112 -0
- package/ai/skills/stacks-security/SKILL.md +129 -0
- package/ai/skills/stacks-security-audit/SKILL.md +128 -0
- package/ai/skills/stacks-server/SKILL.md +458 -0
- package/ai/skills/stacks-shell/SKILL.md +62 -0
- package/ai/skills/stacks-slug/SKILL.md +87 -0
- package/ai/skills/stacks-sms/SKILL.md +385 -0
- package/ai/skills/stacks-socials/SKILL.md +303 -0
- package/ai/skills/stacks-storage/SKILL.md +576 -0
- package/ai/skills/stacks-strings/SKILL.md +416 -0
- package/ai/skills/stacks-stx/SKILL.md +176 -0
- package/ai/skills/stacks-technical-diagrams/LICENSE +22 -0
- package/ai/skills/stacks-technical-diagrams/SKILL.md +290 -0
- package/ai/skills/stacks-technical-diagrams/agents/openai.yaml +4 -0
- package/ai/skills/stacks-technical-diagrams/assets/template.html +1252 -0
- package/ai/skills/stacks-technical-diagrams/bin/technical-diagrams.mjs +289 -0
- package/ai/skills/stacks-technical-diagrams/bunfig.toml +1 -0
- package/ai/skills/stacks-technical-diagrams/examples/agent-run.lifecycle.json +64 -0
- package/ai/skills/stacks-technical-diagrams/examples/agent-tool-call.workflow.json +88 -0
- package/ai/skills/stacks-technical-diagrams/examples/cache-miss-request.sequence.json +75 -0
- package/ai/skills/stacks-technical-diagrams/examples/product-analytics.dataflow.json +70 -0
- package/ai/skills/stacks-technical-diagrams/examples/web-app.architecture.json +41 -0
- package/ai/skills/stacks-technical-diagrams/renderers/architecture/grid.mjs +62 -0
- package/ai/skills/stacks-technical-diagrams/renderers/architecture/render-architecture.mjs +371 -0
- package/ai/skills/stacks-technical-diagrams/renderers/dataflow/README.md +82 -0
- package/ai/skills/stacks-technical-diagrams/renderers/dataflow/render-dataflow.mjs +295 -0
- package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/README.md +91 -0
- package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/render-lifecycle.mjs +384 -0
- package/ai/skills/stacks-technical-diagrams/renderers/sequence/README.md +84 -0
- package/ai/skills/stacks-technical-diagrams/renderers/sequence/render-sequence.mjs +257 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/cli.mjs +42 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/generated-validators.mjs +13 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/geometry.mjs +230 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/layout-report.mjs +40 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/utils.mjs +88 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/validator.mjs +40 -0
- package/ai/skills/stacks-technical-diagrams/renderers/workflow/README.md +103 -0
- package/ai/skills/stacks-technical-diagrams/renderers/workflow/render-workflow.mjs +481 -0
- package/ai/skills/stacks-technical-diagrams/schemas/README.md +68 -0
- package/ai/skills/stacks-technical-diagrams/schemas/architecture.schema.json +121 -0
- package/ai/skills/stacks-technical-diagrams/schemas/common.schema.json +43 -0
- package/ai/skills/stacks-technical-diagrams/schemas/dataflow.schema.json +221 -0
- package/ai/skills/stacks-technical-diagrams/schemas/lifecycle.schema.json +241 -0
- package/ai/skills/stacks-technical-diagrams/schemas/sequence.schema.json +186 -0
- package/ai/skills/stacks-technical-diagrams/schemas/workflow.schema.json +332 -0
- package/ai/skills/stacks-technical-diagrams/scripts/check-render-output.mjs +297 -0
- package/ai/skills/stacks-technical-diagrams/scripts/render-examples.mjs +28 -0
- package/ai/skills/stacks-testing/SKILL.md +129 -0
- package/ai/skills/stacks-tunnel/SKILL.md +125 -0
- package/ai/skills/stacks-types/SKILL.md +178 -0
- package/ai/skills/stacks-ui/SKILL.md +246 -0
- package/ai/skills/stacks-utils/SKILL.md +444 -0
- package/ai/skills/stacks-validation/SKILL.md +371 -0
- package/ai/skills/stacks-whois/SKILL.md +315 -0
- package/assets/world-map-data.ts +121 -0
- package/bootstrap.ts +114 -0
- package/docs/api-examples.md +46 -0
- package/docs/index.md +24 -0
- package/docs/markdown-examples.md +87 -0
- package/functions/analytics.ts +97 -0
- package/functions/api.ts +143 -0
- package/functions/auth.ts +208 -0
- package/functions/billing/payments.ts +149 -0
- package/functions/blog.ts +120 -0
- package/functions/cms/categorizables.ts +107 -0
- package/functions/cms/pages.ts +108 -0
- package/functions/cms/posts.ts +100 -0
- package/functions/cms/taggables.ts +102 -0
- package/functions/commerce/coupons.ts +128 -0
- package/functions/commerce/customers.ts +128 -0
- package/functions/commerce/gift-cards.ts +119 -0
- package/functions/commerce/orders.ts +112 -0
- package/functions/commerce/payments.ts +119 -0
- package/functions/commerce/products/categories.ts +123 -0
- package/functions/commerce/products/manufacturers.ts +123 -0
- package/functions/commerce/products/products.ts +123 -0
- package/functions/commerce/products/reviews.ts +123 -0
- package/functions/commerce/products/units.ts +123 -0
- package/functions/commerce/products/variants.ts +123 -0
- package/functions/commerce/shippings/delivery-routes.ts +123 -0
- package/functions/commerce/shippings/digital-deliveries.ts +119 -0
- package/functions/commerce/shippings/drivers.ts +123 -0
- package/functions/commerce/shippings/license-keys.ts +123 -0
- package/functions/commerce/shippings/shipping-methods.ts +123 -0
- package/functions/commerce/shippings/shipping-rates.ts +119 -0
- package/functions/commerce/shippings/shipping-zones.ts +119 -0
- package/functions/commerce/taxes.ts +119 -0
- package/functions/commerce/waitlist/products.ts +123 -0
- package/functions/commerce/waitlist/restaurants.ts +123 -0
- package/functions/craft.ts +107 -0
- package/functions/dashboard.ts +153 -0
- package/functions/inbox.ts +95 -0
- package/functions/jobs.ts +86 -0
- package/functions/monitoring/errors.ts +295 -0
- package/functions/queue.ts +111 -0
- package/functions/realtime/websockets.ts +96 -0
- package/functions/realtime.ts +52 -0
- package/functions/releases.ts +49 -0
- package/functions/search.ts +126 -0
- package/functions/toasts.ts +95 -0
- package/functions/uploads.ts +216 -0
- package/ide/.gitignore +4 -0
- package/ide/cursor/rules/auto-imports.mdc +574 -0
- package/ide/cursor/rules/code-style.mdc +12 -0
- package/ide/cursor/rules/documentation.mdc +9 -0
- package/ide/cursor/rules/error-handling-validation.mdc +11 -0
- package/ide/cursor/rules/key-conventions.mdc +11 -0
- package/ide/cursor/rules/project-structure.mdc +169 -0
- package/ide/cursor/rules/readme.mdc +318 -0
- package/ide/cursor/rules/syntax-formatting.mdc +9 -0
- package/ide/cursor/rules/testing.mdc +10 -0
- package/ide/cursor/rules/typescript.mdc +9 -0
- package/ide/cursor/rules/ui-styling.mdc +0 -0
- package/ide/dictionary.txt +397 -0
- package/ide/jetbrains/.fleet/settings.json +4 -0
- package/ide/jetbrains/.idea/.gitignore +5 -0
- package/ide/jetbrains/.idea/.name +1 -0
- package/ide/jetbrains/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/ide/jetbrains/.idea/jsLinters/eslint.xml +7 -0
- package/ide/jetbrains/.idea/modules.xml +8 -0
- package/ide/jetbrains/.idea/stacks.iml +22 -0
- package/ide/jetbrains/.idea/vcs.xml +6 -0
- package/ide/jetbrains/.idea/webResources.xml +14 -0
- package/ide/jetbrains/IntelliJ IDEA Global Settings +0 -0
- package/ide/jetbrains/installed.txt +4 -0
- package/ide/jetbrains/options/github-copilot.xml +5 -0
- package/ide/jetbrains/options/nodejs.xml +7 -0
- package/ide/jetbrains/options/templates.xml +124 -0
- package/ide/jetbrains/templates/JavaScript.xml +6 -0
- package/ide/jetbrains/templates/Stacks.xml +8 -0
- package/ide/vscode/.vscode/README.md +23 -0
- package/ide/vscode/.vscode/extensions.json +5 -0
- package/ide/vscode/.vscode/settings.json +176 -0
- package/ide/vscode/.vscode/stacks.code-snippets +181 -0
- package/ide/vscode/LICENSE.md +21 -0
- package/ide/vscode/README.md +36 -0
- package/ide/vscode/logo.png +0 -0
- package/ide/vscode/package.json +79 -0
- package/ide/zed/.zed/settings.json +139 -0
- package/lang/README.md +28 -0
- package/lang/de.yml +14 -0
- package/lang/en.yml +15 -0
- package/package.json +19 -3
- package/project/bootstrap +161 -0
- package/project/buddy +175 -0
- package/project/storage/framework/tsconfig.app.json +50 -0
- package/project/storage/framework/tsconfig.base.json +58 -0
- package/routes/core.ts +78 -0
- package/routes/dashboard-api.ts +233 -0
- package/routes/dashboard.ts +739 -0
- package/routes/email.ts +129 -0
- package/stores/[name].stx +16 -0
- package/stores/git.ts +71 -0
- package/stores/payment.ts +474 -0
- package/stores/queue.ts +43 -0
- package/stores/user.ts +29 -0
- package/stx-components-plugin.ts +25 -0
- package/styles/design-tokens.css +597 -0
- package/types/dashboard.ts +70 -0
- package/types/defaults.ts +438 -0
- package/vcs/github/CODE_OF_CONDUCT.md +83 -0
- package/vcs/github/CONTRIBUTING.md +187 -0
- package/vcs/github/EXPLANATIONS.md +41 -0
- package/vcs/github/FUNDING.yml +1 -0
- package/vcs/github/ISSUE_TEMPLATE/bug_report.yml +49 -0
- package/vcs/github/ISSUE_TEMPLATE/config.yml +10 -0
- package/vcs/github/ISSUE_TEMPLATE/feature_request.yml +44 -0
- package/vcs/github/SECURITY.md +70 -0
- package/vcs/github/renovate.json +5 -0
- package/vcs/github/stale.yml +14 -0
- package/vcs/github/workflows/README.md +16 -0
- package/vcs/github/workflows/ci.yml +114 -0
- package/vcs/github/workflows/export-size.yml +25 -0
- package/vcs/github/workflows/labeler.yml +13 -0
- package/vcs/github/workflows/release.yml +219 -0
- package/views/[...all].stx +8 -0
- package/views/about.md +3 -0
- package/views/auth/login.stx +1 -0
- package/views/auth/signup.stx +85 -0
- package/views/dashboard/.discovered-models.json +542 -0
- package/views/dashboard/AUDIT.md +904 -0
- package/views/dashboard/[...all].stx +89 -0
- package/views/dashboard/access-tokens/index.stx +177 -0
- package/views/dashboard/actions/index.stx +129 -0
- package/views/dashboard/analytics/blog/index.stx +356 -0
- package/views/dashboard/analytics/browsers/index.stx +263 -0
- package/views/dashboard/analytics/commerce/sales/index.stx +329 -0
- package/views/dashboard/analytics/commerce/web/index.stx +379 -0
- package/views/dashboard/analytics/countries/index.stx +289 -0
- package/views/dashboard/analytics/devices/index.stx +305 -0
- package/views/dashboard/analytics/events/index.stx +536 -0
- package/views/dashboard/analytics/index.stx +88 -0
- package/views/dashboard/analytics/marketing/index.stx +315 -0
- package/views/dashboard/analytics/pages/index.stx +271 -0
- package/views/dashboard/analytics/referrers/index.stx +319 -0
- package/views/dashboard/analytics/web/index.stx +356 -0
- package/views/dashboard/buddy/index.stx +198 -0
- package/views/dashboard/ci/index.stx +462 -0
- package/views/dashboard/cloud/index.stx +452 -0
- package/views/dashboard/commands/index.stx +295 -0
- package/views/dashboard/commerce/categories/index.stx +406 -0
- package/views/dashboard/commerce/coupons/index.stx +485 -0
- package/views/dashboard/commerce/customers/index.stx +410 -0
- package/views/dashboard/commerce/dashboard/index.stx +287 -0
- package/views/dashboard/commerce/delivery/delivery-routes.stx +305 -0
- package/views/dashboard/commerce/delivery/digital-delivery.stx +332 -0
- package/views/dashboard/commerce/delivery/drivers.stx +397 -0
- package/views/dashboard/commerce/delivery/index.stx +18 -0
- package/views/dashboard/commerce/delivery/license-keys.stx +380 -0
- package/views/dashboard/commerce/delivery/shipping-methods.stx +346 -0
- package/views/dashboard/commerce/delivery/shipping-rates.stx +338 -0
- package/views/dashboard/commerce/delivery/shipping-zones.stx +302 -0
- package/views/dashboard/commerce/delivery/tabs.ts +25 -0
- package/views/dashboard/commerce/gift-cards/index.stx +561 -0
- package/views/dashboard/commerce/manufacturers/index.stx +308 -0
- package/views/dashboard/commerce/orders/index.stx +247 -0
- package/views/dashboard/commerce/payments/index.stx +535 -0
- package/views/dashboard/commerce/pos/index.stx +653 -0
- package/views/dashboard/commerce/printers/devices/index.stx +273 -0
- package/views/dashboard/commerce/printers/receipts/index.stx +308 -0
- package/views/dashboard/commerce/products/detail.stx +563 -0
- package/views/dashboard/commerce/products/index.stx +370 -0
- package/views/dashboard/commerce/reviews/index.stx +656 -0
- package/views/dashboard/commerce/reviews/index.ts +0 -0
- package/views/dashboard/commerce/taxes/index.stx +377 -0
- package/views/dashboard/commerce/units/index.stx +317 -0
- package/views/dashboard/commerce/variants/index.stx +319 -0
- package/views/dashboard/commerce/waitlist/products.stx +942 -0
- package/views/dashboard/commerce/waitlist/restaurant.stx +1024 -0
- package/views/dashboard/components/index.stx +330 -0
- package/views/dashboard/composables/index.ts +19 -0
- package/views/dashboard/composables/useChart.ts +77 -0
- package/views/dashboard/composables/useNavigation.ts +99 -0
- package/views/dashboard/composables/useRole.ts +58 -0
- package/views/dashboard/composables/useTheme.ts +74 -0
- package/views/dashboard/content/authors/index.stx +171 -0
- package/views/dashboard/content/blog/index.stx +493 -0
- package/views/dashboard/content/categories/index.stx +169 -0
- package/views/dashboard/content/comments/index.stx +189 -0
- package/views/dashboard/content/dashboard.stx +383 -0
- package/views/dashboard/content/files/index.stx +706 -0
- package/views/dashboard/content/pages/index.stx +174 -0
- package/views/dashboard/content/posts/index.stx +269 -0
- package/views/dashboard/content/seo/index.stx +240 -0
- package/views/dashboard/content/tags/index.stx +167 -0
- package/views/dashboard/data/activity/index.stx +261 -0
- package/views/dashboard/data/dashboard/index.stx +116 -0
- package/views/dashboard/data/subscribers.stx +270 -0
- package/views/dashboard/data/teams.stx +275 -0
- package/views/dashboard/data/users.stx +279 -0
- package/views/dashboard/dependencies/index.stx +178 -0
- package/views/dashboard/deployments/[id].stx +234 -0
- package/views/dashboard/deployments/index.stx +9 -0
- package/views/dashboard/dns/index.stx +163 -0
- package/views/dashboard/environment/index.stx +283 -0
- package/views/dashboard/errors/index.stx +274 -0
- package/views/dashboard/forgot-password.stx +57 -0
- package/views/dashboard/functions/index.stx +159 -0
- package/views/dashboard/health/index.stx +248 -0
- package/views/dashboard/inbox/activity.stx +350 -0
- package/views/dashboard/inbox/index.stx +452 -0
- package/views/dashboard/inbox/settings.stx +290 -0
- package/views/dashboard/index.stx +252 -0
- package/views/dashboard/insights/index.stx +529 -0
- package/views/dashboard/jobs/[id].stx +430 -0
- package/views/dashboard/jobs/history.stx +222 -0
- package/views/dashboard/jobs/index.stx +214 -0
- package/views/dashboard/kanban/[id].stx +899 -0
- package/views/dashboard/kanban/index.stx +260 -0
- package/views/dashboard/layouts/default.stx +565 -0
- package/views/dashboard/layouts/guest.stx +10 -0
- package/views/dashboard/login.stx +48 -0
- package/views/dashboard/logs/index.stx +540 -0
- package/views/dashboard/mailboxes/index.stx +149 -0
- package/views/dashboard/management/permissions/index.stx +490 -0
- package/views/dashboard/marketing/campaigns/index.stx +604 -0
- package/views/dashboard/marketing/lists/index.stx +514 -0
- package/views/dashboard/marketing/reviews/index.stx +475 -0
- package/views/dashboard/marketing/social-posts/index.stx +560 -0
- package/views/dashboard/models/[model].stx +195 -0
- package/views/dashboard/models/index.stx +159 -0
- package/views/dashboard/monitoring/errors/index.stx +415 -0
- package/views/dashboard/notifications/dashboard.stx +383 -0
- package/views/dashboard/notifications/email.stx +336 -0
- package/views/dashboard/notifications/history.stx +373 -0
- package/views/dashboard/notifications/sms.stx +332 -0
- package/views/dashboard/packages/index.stx +195 -0
- package/views/dashboard/queries/[id].stx +381 -0
- package/views/dashboard/queries/history.stx +227 -0
- package/views/dashboard/queries/index.stx +335 -0
- package/views/dashboard/queries/slow.stx +318 -0
- package/views/dashboard/queue/index.stx +427 -0
- package/views/dashboard/realtime/index.stx +429 -0
- package/views/dashboard/register.stx +46 -0
- package/views/dashboard/releases/index.stx +389 -0
- package/views/dashboard/requests/index.stx +462 -0
- package/views/dashboard/serverless/index.stx +475 -0
- package/views/dashboard/servers/[id].stx +299 -0
- package/views/dashboard/servers/index.stx +483 -0
- package/views/dashboard/settings/billing.stx +50 -0
- package/views/dashboard/settings/index.stx +256 -0
- package/views/dashboard/settings/mail.stx +252 -0
- package/views/dashboard/stores/auth.ts +123 -0
- package/views/dashboard/stores/ci.ts +342 -0
- package/views/dashboard/stores/index.ts +129 -0
- package/views/dashboard/stores/kanban.ts +723 -0
- package/views/dashboard/stores/rbac.ts +350 -0
- package/views/dashboard/stx.config.ts +34 -0
- package/views/dashboard/teams/[id].stx +170 -0
- package/views/forum/category.stx +92 -0
- package/views/forum/index.stx +209 -0
- package/views/forum/new-topic.stx +113 -0
- package/views/forum/profile.stx +1 -0
- package/views/forum/topic.stx +143 -0
- package/views/hello-world/[name].stx +47 -0
- package/views/index.stx +21 -0
- package/views/system-tray/index.stx +147 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
@extends('layouts/default')
|
|
2
|
+
|
|
3
|
+
@section('content')
|
|
4
|
+
@title('Dashboard - Commerce Customers')
|
|
5
|
+
<div class="p-6 space-y-6">
|
|
6
|
+
|
|
7
|
+
<PageHeader title="Customers" description="Manage your store customers">
|
|
8
|
+
<template #actions>
|
|
9
|
+
<Button variant="primary" @click="openAddModal()">
|
|
10
|
+
<div class="h-4 w-4 i-hugeicons-plus-sign"></div>
|
|
11
|
+
Add Customer
|
|
12
|
+
</Button>
|
|
13
|
+
</template>
|
|
14
|
+
</PageHeader>
|
|
15
|
+
|
|
16
|
+
<div class="overflow-hidden bg-white dark:bg-neutral-800 rounded-lg shadow">
|
|
17
|
+
<div class="px-4 py-5 sm:px-6 border-b border-gray-200 dark:border-neutral-700">
|
|
18
|
+
<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between mt-4">
|
|
19
|
+
<SearchFilter
|
|
20
|
+
placeholder="Search customers..."
|
|
21
|
+
@search="handleSearch"
|
|
22
|
+
class="w-full md:w-96"
|
|
23
|
+
/>
|
|
24
|
+
<div class="flex flex-col gap-4 sm:flex-row">
|
|
25
|
+
<select
|
|
26
|
+
x-model="statusFilter"
|
|
27
|
+
class="block pl-3 pr-10 py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white dark:bg-neutral-800 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-700 focus:ring-2 focus:ring-blue-600 focus:ring-inset"
|
|
28
|
+
>
|
|
29
|
+
<template :for="status in statuses">
|
|
30
|
+
<option :value="status">{{ status }}</option>
|
|
31
|
+
</template>
|
|
32
|
+
</select>
|
|
33
|
+
|
|
34
|
+
<select
|
|
35
|
+
x-model.number="itemsPerPage"
|
|
36
|
+
class="block pl-3 pr-10 py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white dark:bg-neutral-800 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-700 focus:ring-2 focus:ring-blue-600 focus:ring-inset"
|
|
37
|
+
>
|
|
38
|
+
<option value="5">5 per page</option>
|
|
39
|
+
<option value="10">10 per page</option>
|
|
40
|
+
<option value="25">25 per page</option>
|
|
41
|
+
<option value="50">50 per page</option>
|
|
42
|
+
</select>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<!-- Customer Tables Component -->
|
|
48
|
+
<CustomersTable
|
|
49
|
+
:customers="paginatedCustomers()"
|
|
50
|
+
:searchQuery="searchQuery()"
|
|
51
|
+
:statusFilter="statusFilter()"
|
|
52
|
+
:sortBy="sortBy()"
|
|
53
|
+
:sortOrder="sortOrder()"
|
|
54
|
+
:currentPage="currentPage()"
|
|
55
|
+
:itemsPerPage="itemsPerPage()"
|
|
56
|
+
:statuses="statuses"
|
|
57
|
+
@toggle-sort="toggleSort"
|
|
58
|
+
@change-page="handlePageChange"
|
|
59
|
+
@previous-page="handlePrevPage"
|
|
60
|
+
@next-page="handleNextPage"
|
|
61
|
+
@view-customer="viewCustomer"
|
|
62
|
+
@edit-customer="editCustomer"
|
|
63
|
+
@delete-customer="removeCustomer"
|
|
64
|
+
/>
|
|
65
|
+
|
|
66
|
+
<div class="px-4 py-3 bg-gray-50 dark:bg-neutral-900 border-gray-200 border-t dark:border-neutral-700">
|
|
67
|
+
<Pagination
|
|
68
|
+
:currentPage="currentPage()"
|
|
69
|
+
:totalItems="filteredCustomers().length"
|
|
70
|
+
:itemsPerPage="itemsPerPage()"
|
|
71
|
+
@prev="handlePrevPage"
|
|
72
|
+
@next="handleNextPage"
|
|
73
|
+
@page="handlePageChange"
|
|
74
|
+
/>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<!-- Add Customer Modal -->
|
|
80
|
+
<div :show="showAddModal" class="fixed inset-0 overflow-y-auto z-10">
|
|
81
|
+
<div class="flex items-end justify-center sm:items-center p-4 sm:p-0 min-h-full text-center">
|
|
82
|
+
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" @click="closeAddModal()"></div>
|
|
83
|
+
|
|
84
|
+
<div class="overflow-hidden relative pb-4 pt-5 px-4 sm:my-8 sm:p-6 sm:max-w-lg sm:w-full text-left bg-white dark:bg-neutral-800 rounded-lg shadow-xl transition-all transform">
|
|
85
|
+
<div>
|
|
86
|
+
<div class="mt-3 sm:mt-5 text-center">
|
|
87
|
+
<h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Add New Customer</h3>
|
|
88
|
+
<div class="mt-4">
|
|
89
|
+
<div class="space-y-4">
|
|
90
|
+
<div>
|
|
91
|
+
<label for="customer-name" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Full Name</label>
|
|
92
|
+
<div class="mt-2">
|
|
93
|
+
<input
|
|
94
|
+
type="text"
|
|
95
|
+
id="customer-name"
|
|
96
|
+
x-model="newCustomerName"
|
|
97
|
+
class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm"
|
|
98
|
+
placeholder="Enter customer name"
|
|
99
|
+
/>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<div>
|
|
104
|
+
<label for="customer-email" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Email Address</label>
|
|
105
|
+
<div class="mt-2">
|
|
106
|
+
<input
|
|
107
|
+
type="email"
|
|
108
|
+
id="customer-email"
|
|
109
|
+
x-model="newCustomerEmail"
|
|
110
|
+
class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm"
|
|
111
|
+
placeholder="Enter email address"
|
|
112
|
+
/>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<div>
|
|
117
|
+
<label for="customer-phone" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Phone Number</label>
|
|
118
|
+
<div class="mt-2">
|
|
119
|
+
<input
|
|
120
|
+
type="tel"
|
|
121
|
+
id="customer-phone"
|
|
122
|
+
x-model="newCustomerPhone"
|
|
123
|
+
class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white placeholder:text-gray-400 dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm"
|
|
124
|
+
placeholder="Enter phone number"
|
|
125
|
+
/>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<div>
|
|
130
|
+
<label for="customer-status" class="block font-medium leading-6 text-gray-900 text-left text-sm dark:text-neutral-200">Status</label>
|
|
131
|
+
<div class="mt-2">
|
|
132
|
+
<select
|
|
133
|
+
id="customer-status"
|
|
134
|
+
x-model="newCustomerStatus"
|
|
135
|
+
class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-white dark:bg-neutral-700 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm"
|
|
136
|
+
>
|
|
137
|
+
<template :for="status in statuses">
|
|
138
|
+
<option :value="status">{{ status }}</option>
|
|
139
|
+
</template>
|
|
140
|
+
</select>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
<div class="sm:grid sm:gap-3 sm:grid-cols-2 sm:grid-flow-row-dense mt-5 sm:mt-6">
|
|
148
|
+
<button
|
|
149
|
+
type="button"
|
|
150
|
+
@click="addCustomer()"
|
|
151
|
+
class="inline-flex justify-center sm:col-start-2 px-3 py-2 w-full font-semibold text-sm text-white bg-blue-600 hover:bg-blue-500 rounded-md focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2 shadow-sm"
|
|
152
|
+
>
|
|
153
|
+
Add Customer
|
|
154
|
+
</button>
|
|
155
|
+
<button
|
|
156
|
+
type="button"
|
|
157
|
+
@click="closeAddModal()"
|
|
158
|
+
class="inline-flex justify-center sm:col-start-1 mt-3 px-3 py-2 sm:mt-0 w-full font-semibold text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 hover:bg-gray-50 dark:hover:bg-neutral-600 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 shadow-sm"
|
|
159
|
+
>
|
|
160
|
+
Cancel
|
|
161
|
+
</button>
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
<!-- Delete Customer Confirmation Modal -->
|
|
168
|
+
<div :show="showDeleteModal" class="fixed inset-0 overflow-y-auto z-10">
|
|
169
|
+
<div class="flex items-end justify-center sm:items-center p-4 sm:p-0 min-h-full text-center">
|
|
170
|
+
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" @click="closeDeleteModal()"></div>
|
|
171
|
+
|
|
172
|
+
<div class="overflow-hidden relative pb-4 pt-5 px-4 sm:my-8 sm:p-6 sm:max-w-lg sm:w-full text-left bg-white dark:bg-neutral-800 rounded-lg shadow-xl transition-all transform">
|
|
173
|
+
<div>
|
|
174
|
+
<div class="flex items-center justify-center mx-auto h-12 w-12 bg-red-100 dark:bg-red-900 rounded-full">
|
|
175
|
+
<div class="h-6 w-6 text-red-600 dark:text-red-400 i-hugeicons-alert-triangle"></div>
|
|
176
|
+
</div>
|
|
177
|
+
<div class="mt-3 sm:mt-5 text-center">
|
|
178
|
+
<h3 class="font-semibold leading-6 text-base text-gray-900 dark:text-white">Delete Customer</h3>
|
|
179
|
+
<div class="mt-2">
|
|
180
|
+
<p class="text-gray-500 text-sm dark:text-neutral-400">
|
|
181
|
+
Are you sure you want to delete <strong>{{ customerToDelete()?.name }}</strong>? This action cannot be undone.
|
|
182
|
+
</p>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
</div>
|
|
186
|
+
<div class="sm:grid sm:gap-3 sm:grid-cols-2 sm:grid-flow-row-dense mt-5 sm:mt-6">
|
|
187
|
+
<button
|
|
188
|
+
type="button"
|
|
189
|
+
@click="confirmDelete()"
|
|
190
|
+
class="inline-flex justify-center sm:col-start-2 px-3 py-2 w-full font-semibold text-sm text-white bg-red-600 hover:bg-red-500 rounded-md focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600 shadow-sm"
|
|
191
|
+
>
|
|
192
|
+
Delete Customer
|
|
193
|
+
</button>
|
|
194
|
+
<button
|
|
195
|
+
type="button"
|
|
196
|
+
@click="closeDeleteModal()"
|
|
197
|
+
class="inline-flex justify-center sm:col-start-1 mt-3 px-3 py-2 sm:mt-0 w-full font-semibold text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-700 hover:bg-gray-50 dark:hover:bg-neutral-600 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 shadow-sm"
|
|
198
|
+
>
|
|
199
|
+
Cancel
|
|
200
|
+
</button>
|
|
201
|
+
</div>
|
|
202
|
+
</div>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
|
|
207
|
+
<script client>
|
|
208
|
+
import { useCustomers } from '../../../../functions/commerce/customers'
|
|
209
|
+
// Filter options — moved out of the former `<script server>` block
|
|
210
|
+
// (stacksjs/stacks#1838).
|
|
211
|
+
const statuses = ['all', 'Active', 'Inactive'] as const
|
|
212
|
+
|
|
213
|
+
interface Customer {
|
|
214
|
+
id: number
|
|
215
|
+
name: string
|
|
216
|
+
email: string
|
|
217
|
+
phone: string
|
|
218
|
+
total_spent?: number
|
|
219
|
+
last_order?: string
|
|
220
|
+
status: string
|
|
221
|
+
avatar?: string
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// useCustomers wraps a useStorage ref + REST helpers. Keep it as the
|
|
225
|
+
// single source of truth for the customers list — wrap reads in a
|
|
226
|
+
// derived signal so template bindings re-render when the underlying
|
|
227
|
+
// ref mutates (push / splice / replace).
|
|
228
|
+
const { customers, createCustomer, fetchCustomers, deleteCustomer } = useCustomers()
|
|
229
|
+
|
|
230
|
+
// Filtering + sorting + pagination state — local to this page.
|
|
231
|
+
const statusFilter = state<'all' | 'Active' | 'Inactive'>('all')
|
|
232
|
+
const sortBy = state<'name' | 'total_spent' | 'last_order'>('name')
|
|
233
|
+
const sortOrder = state<'asc' | 'desc'>('asc')
|
|
234
|
+
const searchQuery = state('')
|
|
235
|
+
const currentPage = state(1)
|
|
236
|
+
const itemsPerPage = state(5)
|
|
237
|
+
|
|
238
|
+
// Modal state. Splitting newCustomer into discrete signals keeps each
|
|
239
|
+
// <input x-model> binding a single signal — simpler than wiring nested
|
|
240
|
+
// object updates through `update(o => ({ ...o, ... }))` per field.
|
|
241
|
+
const showAddModal = state(false)
|
|
242
|
+
const showDeleteModal = state(false)
|
|
243
|
+
const customerToDelete = state<Customer | null>(null)
|
|
244
|
+
const newCustomerName = state('')
|
|
245
|
+
const newCustomerEmail = state('')
|
|
246
|
+
const newCustomerPhone = state('')
|
|
247
|
+
const newCustomerStatus = state<'Active' | 'Inactive'>('Active')
|
|
248
|
+
|
|
249
|
+
const filteredCustomers = derived(() => {
|
|
250
|
+
const q = searchQuery().toLowerCase()
|
|
251
|
+
const filter = statusFilter()
|
|
252
|
+
const by = sortBy()
|
|
253
|
+
const dir = sortOrder()
|
|
254
|
+
|
|
255
|
+
return (customers.value as Customer[])
|
|
256
|
+
.filter((c) => {
|
|
257
|
+
const matchesSearch
|
|
258
|
+
= c.name.toLowerCase().includes(q)
|
|
259
|
+
|| c.email.toLowerCase().includes(q)
|
|
260
|
+
|| c.phone.toLowerCase().includes(q)
|
|
261
|
+
const matchesStatus = filter === 'all' || c.status === filter
|
|
262
|
+
return matchesSearch && matchesStatus
|
|
263
|
+
})
|
|
264
|
+
.sort((a, b) => {
|
|
265
|
+
let cmp = 0
|
|
266
|
+
if (by === 'name') {
|
|
267
|
+
cmp = a.name.localeCompare(b.name)
|
|
268
|
+
}
|
|
269
|
+
else if (by === 'total_spent') {
|
|
270
|
+
cmp = (a.total_spent || 0) - (b.total_spent || 0)
|
|
271
|
+
}
|
|
272
|
+
else if (by === 'last_order') {
|
|
273
|
+
const dateA = a.last_order ? new Date(a.last_order).getTime() : 0
|
|
274
|
+
const dateB = b.last_order ? new Date(b.last_order).getTime() : 0
|
|
275
|
+
cmp = dateA - dateB
|
|
276
|
+
}
|
|
277
|
+
return dir === 'asc' ? cmp : -cmp
|
|
278
|
+
})
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
const paginatedCustomers = derived(() => {
|
|
282
|
+
const start = (currentPage() - 1) * itemsPerPage()
|
|
283
|
+
const end = start + itemsPerPage()
|
|
284
|
+
return filteredCustomers().slice(start, end)
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
function handleSearch(query: string): void {
|
|
288
|
+
searchQuery.set(query)
|
|
289
|
+
currentPage.set(1)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function handlePrevPage(): void {
|
|
293
|
+
if (currentPage() > 1)
|
|
294
|
+
currentPage.update(p => p - 1)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function handleNextPage(): void {
|
|
298
|
+
const totalPages = Math.ceil(filteredCustomers().length / itemsPerPage())
|
|
299
|
+
if (currentPage() < totalPages)
|
|
300
|
+
currentPage.update(p => p + 1)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function handlePageChange(page: number): void {
|
|
304
|
+
currentPage.set(page)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function toggleSort(column: 'name' | 'total_spent' | 'last_order'): void {
|
|
308
|
+
if (sortBy() === column) {
|
|
309
|
+
sortOrder.update(d => d === 'asc' ? 'desc' : 'asc')
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
sortBy.set(column)
|
|
313
|
+
sortOrder.set('asc')
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Customer actions — `navigate` is auto-imported.
|
|
318
|
+
function viewCustomer(c: Customer): void {
|
|
319
|
+
navigate(`/dashboard/commerce/customers/${c.id}`)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function editCustomer(c: Customer): void {
|
|
323
|
+
navigate(`/dashboard/commerce/customers/${c.id}?edit=true`)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function removeCustomer(c: Customer): void {
|
|
327
|
+
customerToDelete.set(c)
|
|
328
|
+
showDeleteModal.set(true)
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function openAddModal(): void {
|
|
332
|
+
newCustomerName.set('')
|
|
333
|
+
newCustomerEmail.set('')
|
|
334
|
+
newCustomerPhone.set('')
|
|
335
|
+
newCustomerStatus.set('Active')
|
|
336
|
+
showAddModal.set(true)
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function closeAddModal(): void {
|
|
340
|
+
showAddModal.set(false)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function closeDeleteModal(): void {
|
|
344
|
+
showDeleteModal.set(false)
|
|
345
|
+
customerToDelete.set(null)
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
async function confirmDelete(): Promise<void> {
|
|
349
|
+
const target = customerToDelete()
|
|
350
|
+
if (!target)
|
|
351
|
+
return
|
|
352
|
+
|
|
353
|
+
const id = target.id
|
|
354
|
+
const list = customers.value as Customer[]
|
|
355
|
+
customers.value = list.filter(c => c.id !== id)
|
|
356
|
+
|
|
357
|
+
try {
|
|
358
|
+
await deleteCustomer(id)
|
|
359
|
+
closeDeleteModal()
|
|
360
|
+
}
|
|
361
|
+
catch (error) {
|
|
362
|
+
customers.value = [...customers.value, target]
|
|
363
|
+
// eslint-disable-next-line no-console
|
|
364
|
+
console.error('Failed to delete customer:', error)
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
async function addCustomer(): Promise<void> {
|
|
369
|
+
const list = customers.value as Customer[]
|
|
370
|
+
const id = list.length > 0 ? Math.max(...list.map(c => c.id || 0)) + 1 : 1
|
|
371
|
+
const today = new Date().toISOString().split('T')[0] || ''
|
|
372
|
+
const avatar = 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80'
|
|
373
|
+
|
|
374
|
+
const optimistic: Customer = {
|
|
375
|
+
id,
|
|
376
|
+
name: newCustomerName(),
|
|
377
|
+
email: newCustomerEmail(),
|
|
378
|
+
phone: newCustomerPhone(),
|
|
379
|
+
total_spent: 0,
|
|
380
|
+
last_order: today,
|
|
381
|
+
status: newCustomerStatus(),
|
|
382
|
+
avatar,
|
|
383
|
+
}
|
|
384
|
+
customers.value = [...list, optimistic]
|
|
385
|
+
|
|
386
|
+
try {
|
|
387
|
+
await createCustomer({
|
|
388
|
+
name: optimistic.name,
|
|
389
|
+
email: optimistic.email,
|
|
390
|
+
phone: optimistic.phone,
|
|
391
|
+
total_spent: 0,
|
|
392
|
+
last_order: today,
|
|
393
|
+
status: optimistic.status,
|
|
394
|
+
avatar,
|
|
395
|
+
})
|
|
396
|
+
closeAddModal()
|
|
397
|
+
}
|
|
398
|
+
catch (error) {
|
|
399
|
+
customers.value = (customers.value as Customer[]).filter(c => c.id !== id)
|
|
400
|
+
// eslint-disable-next-line no-console
|
|
401
|
+
console.error('Failed to create customer:', error)
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
onMount(async () => {
|
|
406
|
+
await fetchCustomers()
|
|
407
|
+
})
|
|
408
|
+
</script>
|
|
409
|
+
|
|
410
|
+
@endsection
|