@stacksjs/defaults 0.70.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/LICENSE.md +21 -0
- package/README.md +2 -0
- package/package.json +20 -0
- package/resources/assets/fonts/013717e9.woff +0 -0
- package/resources/assets/fonts/03355817.woff2 +0 -0
- package/resources/assets/fonts/0380de7e.woff2 +0 -0
- package/resources/assets/fonts/0ba5d32a.woff +0 -0
- package/resources/assets/fonts/0bd57ddf.woff2 +0 -0
- package/resources/assets/fonts/19de0a60.woff2 +0 -0
- package/resources/assets/fonts/20b87e84.woff +0 -0
- package/resources/assets/fonts/4bbc67e1.woff +0 -0
- package/resources/assets/fonts/576fb0d7.woff +0 -0
- package/resources/assets/fonts/5ea10ee5.woff2 +0 -0
- package/resources/assets/fonts/6413fc0a.woff +0 -0
- package/resources/assets/fonts/72c114cf.woff +0 -0
- package/resources/assets/fonts/73c57e73.woff2 +0 -0
- package/resources/assets/fonts/813dca6c.woff +0 -0
- package/resources/assets/fonts/8a9b0995.woff2 +0 -0
- package/resources/assets/fonts/90b4832f.woff +0 -0
- package/resources/assets/fonts/9394ab85.woff2 +0 -0
- package/resources/assets/fonts/9b3c7d7f.woff2 +0 -0
- package/resources/assets/fonts/Monaco.ttf +0 -0
- package/resources/assets/fonts/b1b36d74.woff +0 -0
- package/resources/assets/fonts/b5d74798.woff2 +0 -0
- package/resources/assets/fonts/b9f81a4d.woff +0 -0
- package/resources/assets/fonts/c9784008.woff2 +0 -0
- package/resources/assets/fonts/cf692227.woff +0 -0
- package/resources/assets/fonts/d1c6ab51.woff2 +0 -0
- package/resources/assets/fonts/e2eb62fc.woff +0 -0
- package/resources/assets/fonts/fe21f8d8.woff2 +0 -0
- package/resources/assets/fonts/nps/CampmateScript-Regular.woff2 +0 -0
- package/resources/assets/fonts/nps/NPS_2026-variable.woff2 +0 -0
- package/resources/assets/fonts/nps/RedwoodSerif-Regular.woff2 +0 -0
- package/resources/assets/fonts/nps/SequoiaSans-Regular.woff2 +0 -0
- package/resources/assets/fonts/nps/Switchback-Regular.woff2 +0 -0
- package/resources/assets/images/app-icon.png +0 -0
- package/resources/assets/images/bg-img.png +0 -0
- package/resources/assets/images/park-ridge.svg +15 -0
- package/resources/assets/images/topography.svg +1 -0
- package/resources/assets/scripts/main.ts +2153 -0
- package/resources/assets/styles/README.md +19 -0
- package/resources/assets/styles/docs/main.css +1 -0
- package/resources/assets/styles/docs/overrides.css +1 -0
- package/resources/assets/styles/docs/vars.css +8 -0
- package/resources/assets/styles/main.css +1419 -0
- package/resources/components/Button.stx +70 -0
- package/resources/components/Buttons/BaseButton.stx +39 -0
- package/resources/components/Buttons/Counter.stx +28 -0
- package/resources/components/Buttons/ToggleDark.stx +11 -0
- package/resources/components/Container.stx +10 -0
- package/resources/components/Dashboard/.gitkeep +0 -0
- package/resources/components/Dashboard/Auth/ForgotPassword.stx +127 -0
- package/resources/components/Dashboard/Auth/Login.stx +212 -0
- package/resources/components/Dashboard/Auth/Register.stx +306 -0
- package/resources/components/Dashboard/Avatar.stx +123 -0
- package/resources/components/Dashboard/Billing/ActivePlan.stx +57 -0
- package/resources/components/Dashboard/Billing/CardBrands.stx +32 -0
- package/resources/components/Dashboard/Billing/CardForm.stx +34 -0
- package/resources/components/Dashboard/Billing/OneTimePayment.stx +28 -0
- package/resources/components/Dashboard/Billing/PaymentForm.stx +33 -0
- package/resources/components/Dashboard/Billing/PaymentMethod.stx +66 -0
- package/resources/components/Dashboard/Billing/PaymentMethodList.stx +52 -0
- package/resources/components/Dashboard/Billing/Plans.stx +136 -0
- package/resources/components/Dashboard/Buttons/AppButton.stx +48 -0
- package/resources/components/Dashboard/Buttons/IconButton.stx +20 -0
- package/resources/components/Dashboard/Card.stx +78 -0
- package/resources/components/Dashboard/Chart.stx +75 -0
- package/resources/components/Dashboard/CodeEditor.stx +41 -0
- package/resources/components/Dashboard/Commerce/BulkActionBar.stx +70 -0
- package/resources/components/Dashboard/Commerce/CategoriesTable.stx +133 -0
- package/resources/components/Dashboard/Commerce/CouponsTable.stx +161 -0
- package/resources/components/Dashboard/Commerce/CustomersTable.stx +142 -0
- package/resources/components/Dashboard/Commerce/Delivery/DeliveryRoutesTable.stx +80 -0
- package/resources/components/Dashboard/Commerce/Delivery/DigitalDeliveryTable.stx +85 -0
- package/resources/components/Dashboard/Commerce/Delivery/DriversTable.stx +99 -0
- package/resources/components/Dashboard/Commerce/Delivery/LicenseKeysTable.stx +92 -0
- package/resources/components/Dashboard/Commerce/Delivery/LicenseTemplatesTable.stx +88 -0
- package/resources/components/Dashboard/Commerce/Delivery/Pagination.stx +122 -0
- package/resources/components/Dashboard/Commerce/Delivery/SearchFilter.stx +23 -0
- package/resources/components/Dashboard/Commerce/Delivery/ShippingMethodsTable.stx +80 -0
- package/resources/components/Dashboard/Commerce/Delivery/ShippingRatesTable.stx +59 -0
- package/resources/components/Dashboard/Commerce/Delivery/ShippingZonesTable.stx +71 -0
- package/resources/components/Dashboard/Commerce/Delivery/TabNavigation.stx +36 -0
- package/resources/components/Dashboard/Commerce/Forms/CouponsForm.stx +191 -0
- package/resources/components/Dashboard/Commerce/OrdersTable.stx +131 -0
- package/resources/components/Dashboard/Commerce/ProductsTable.stx +170 -0
- package/resources/components/Dashboard/CreateRecordModal.stx +363 -0
- package/resources/components/Dashboard/DashboardLayout.stx +155 -0
- package/resources/components/Dashboard/Deployments/ActivityFeed.stx +54 -0
- package/resources/components/Dashboard/Deployments/DeployScript.stx +23 -0
- package/resources/components/Dashboard/Deployments/DeploymentHistory.stx +97 -0
- package/resources/components/Dashboard/Deployments/DeploymentList.stx +94 -0
- package/resources/components/Dashboard/Deployments/LiveTerminalOutput.stx +18 -0
- package/resources/components/Dashboard/Elements/Dropdown.stx +57 -0
- package/resources/components/Dashboard/Email/EmailActivityChart.stx +111 -0
- package/resources/components/Dashboard/Email/EmailCompose.stx +72 -0
- package/resources/components/Dashboard/Email/EmailDetail.stx +105 -0
- package/resources/components/Dashboard/Email/EmailList.stx +117 -0
- package/resources/components/Dashboard/Email/EmailSearch.stx +40 -0
- package/resources/components/Dashboard/Email/EmailSidebar.stx +133 -0
- package/resources/components/Dashboard/GlobalSearch.stx +124 -0
- package/resources/components/Dashboard/MobileSidebar.stx +47 -0
- package/resources/components/Dashboard/Modals/BaseModal.stx +50 -0
- package/resources/components/Dashboard/Modals/Popups/Alert.stx +112 -0
- package/resources/components/Dashboard/Modals/Popups/Toast.stx +70 -0
- package/resources/components/Dashboard/Modals/ToastWrapper.stx +35 -0
- package/resources/components/Dashboard/Monitoring/ErrorDetailModal.stx +228 -0
- package/resources/components/Dashboard/Monitoring/ErrorsTable.stx +184 -0
- package/resources/components/Dashboard/Navbar.stx +194 -0
- package/resources/components/Dashboard/NavbarModern.stx +188 -0
- package/resources/components/Dashboard/NotificationErrorModal.stx +105 -0
- package/resources/components/Dashboard/NotificationStatusBadge.stx +20 -0
- package/resources/components/Dashboard/Pagination.stx +90 -0
- package/resources/components/Dashboard/Queue/QueueTable.stx +127 -0
- package/resources/components/Dashboard/Settings/Forms/AIForm.stx +126 -0
- package/resources/components/Dashboard/Settings/Forms/AnalyticsForm.stx +52 -0
- package/resources/components/Dashboard/Settings/Forms/AppForm.stx +157 -0
- package/resources/components/Dashboard/Settings/Forms/CLIForm.stx +66 -0
- package/resources/components/Dashboard/Settings/Forms/CacheForm.stx +253 -0
- package/resources/components/Dashboard/Settings/Forms/CloudForm.stx +441 -0
- package/resources/components/Dashboard/Settings/Forms/DNSForm.stx +307 -0
- package/resources/components/Dashboard/Settings/Forms/DatabaseForm.stx +168 -0
- package/resources/components/Dashboard/Settings/Forms/EmailForm.stx +100 -0
- package/resources/components/Dashboard/Settings/Forms/FileSystemForm.stx +259 -0
- package/resources/components/Dashboard/Settings/Forms/HashingForm.stx +119 -0
- package/resources/components/Dashboard/Settings/Forms/LibraryForm.stx +389 -0
- package/resources/components/Dashboard/Settings/Forms/QueueForm.stx +219 -0
- package/resources/components/Dashboard/Settings/Forms/SearchEngineForm.stx +48 -0
- package/resources/components/Dashboard/Settings/Forms/SecurityForm.stx +143 -0
- package/resources/components/Dashboard/Settings/Forms/ServicesForm.stx +194 -0
- package/resources/components/Dashboard/Settings/Forms/StorageForm.stx +191 -0
- package/resources/components/Dashboard/Settings/Forms/TeamsForm.stx +33 -0
- package/resources/components/Dashboard/Settings/SettingsFormManager.stx +181 -0
- package/resources/components/Dashboard/SettingsHeader.stx +88 -0
- package/resources/components/Dashboard/SettingsSidebar.stx +234 -0
- package/resources/components/Dashboard/Sidebar.stx +23 -0
- package/resources/components/Dashboard/SidebarModern.stx +249 -0
- package/resources/components/Dashboard/Skeleton/LoadingCard.stx +15 -0
- package/resources/components/Dashboard/Skeleton/LoadingDetails.stx +26 -0
- package/resources/components/Dashboard/Table.stx +82 -0
- package/resources/components/Dashboard/TerminalContainer.stx +97 -0
- package/resources/components/Dashboard/Tooltip.stx +166 -0
- package/resources/components/Dashboard/Transaction/index.stx +88 -0
- package/resources/components/Dashboard/UI/ActivityTable.stx +54 -0
- package/resources/components/Dashboard/UI/Avatar.stx +102 -0
- package/resources/components/Dashboard/UI/Badge.stx +66 -0
- package/resources/components/Dashboard/UI/Button.stx +73 -0
- package/resources/components/Dashboard/UI/Card.stx +51 -0
- package/resources/components/Dashboard/UI/ChartCard.stx +36 -0
- package/resources/components/Dashboard/UI/Checkbox.stx +74 -0
- package/resources/components/Dashboard/UI/ConfirmDialog.stx +74 -0
- package/resources/components/Dashboard/UI/DataTable.stx +45 -0
- package/resources/components/Dashboard/UI/Dropdown.stx +72 -0
- package/resources/components/Dashboard/UI/DropdownItem.stx +80 -0
- package/resources/components/Dashboard/UI/EmptyState.stx +50 -0
- package/resources/components/Dashboard/UI/FilterBar.stx +48 -0
- package/resources/components/Dashboard/UI/Input.stx +77 -0
- package/resources/components/Dashboard/UI/Modal.stx +75 -0
- package/resources/components/Dashboard/UI/PageHeader.stx +69 -0
- package/resources/components/Dashboard/UI/PageLayout.stx +84 -0
- package/resources/components/Dashboard/UI/Pagination.stx +126 -0
- package/resources/components/Dashboard/UI/QuickLinks.stx +31 -0
- package/resources/components/Dashboard/UI/RouterLink.stx +31 -0
- package/resources/components/Dashboard/UI/Select.stx +84 -0
- package/resources/components/Dashboard/UI/ServiceHealth.stx +38 -0
- package/resources/components/Dashboard/UI/StatsCard.stx +79 -0
- package/resources/components/Dashboard/UI/Table.stx +143 -0
- package/resources/components/Dashboard/UI/Tabs.stx +45 -0
- package/resources/components/Dashboard/UI/Textarea.stx +93 -0
- package/resources/components/Dashboard/UI/Toggle.stx +84 -0
- package/resources/components/Dashboard/UI/WindowControls.stx +135 -0
- package/resources/components/Dashboard/Widget.stx +89 -0
- package/resources/components/Dashboard/WindowControls.stx +119 -0
- package/resources/components/Dashboard/index.ts +106 -0
- package/resources/components/Docs/Demo/ComboboxCode.md +114 -0
- package/resources/components/Docs/Demo/ComboboxDemo.stx +91 -0
- package/resources/components/Docs/Demo/DialogCode.md +42 -0
- package/resources/components/Docs/Demo/DialogDemo.stx +76 -0
- package/resources/components/Docs/Demo/DocsPlayground.stx +39 -0
- package/resources/components/Docs/Demo/DropdownCode.md +109 -0
- package/resources/components/Docs/Demo/DropdownDemo.stx +82 -0
- package/resources/components/Docs/Demo/Hero.stx +100 -0
- package/resources/components/Docs/Demo/ListboxCode.md +87 -0
- package/resources/components/Docs/Demo/ListboxDemo.stx +59 -0
- package/resources/components/Docs/Demo/NotificationCode.md +173 -0
- package/resources/components/Docs/Demo/NotificationDemo.stx +99 -0
- package/resources/components/Docs/Demo/PopoverCode.md +161 -0
- package/resources/components/Docs/Demo/PopoverDemo.stx +96 -0
- package/resources/components/Docs/Demo/RadioGroupCode.md +98 -0
- package/resources/components/Docs/Demo/RadioGroupDemo.stx +53 -0
- package/resources/components/Docs/Demo/StepperCode.md +216 -0
- package/resources/components/Docs/Demo/StepperDemo.stx +137 -0
- package/resources/components/Docs/Demo/SwitchCode.md +24 -0
- package/resources/components/Docs/Demo/SwitchDemo.stx +28 -0
- package/resources/components/Docs/Home.stx +7 -0
- package/resources/components/Docs/HomeContributors.stx +23 -0
- package/resources/components/Docs/HomeSponsors.stx +17 -0
- package/resources/components/Docs/HomeTeam.stx +18 -0
- package/resources/components/Docs/TeamMember.stx +79 -0
- package/resources/components/Email/EmailButton.stx +32 -0
- package/resources/components/Email/EmailDivider.stx +20 -0
- package/resources/components/Email/EmailImage.stx +24 -0
- package/resources/components/Email/EmailLayout.stx +55 -0
- package/resources/components/Email/EmailLink.stx +22 -0
- package/resources/components/Email/EmailSection.stx +20 -0
- package/resources/components/Email/EmailText.stx +30 -0
- package/resources/components/Forum/ForumBreadcrumb.stx +38 -0
- package/resources/components/Forum/ForumCategory.stx +16 -0
- package/resources/components/Forum/ForumCategoryItem.stx +46 -0
- package/resources/components/Forum/ForumLayout.stx +36 -0
- package/resources/components/Forum/ForumPagination.stx +39 -0
- package/resources/components/Forum/ForumPost.stx +71 -0
- package/resources/components/Forum/ForumReplyForm.stx +76 -0
- package/resources/components/Forum/ForumSidebar.stx +86 -0
- package/resources/components/Forum/ForumTopicItem.stx +77 -0
- package/resources/components/Forum/ForumTopicList.stx +23 -0
- package/resources/components/HelloWorld.stx +253 -0
- package/resources/components/Logo.stx +10 -0
- package/resources/components/Marketing/CallToAction.stx +30 -0
- package/resources/components/Marketing/ComingSoon.stx +155 -0
- package/resources/components/Marketing/Faqs.stx +99 -0
- package/resources/components/Marketing/Feature.stx +32 -0
- package/resources/components/Marketing/Fields.stx +28 -0
- package/resources/components/Marketing/Footer.stx +33 -0
- package/resources/components/Marketing/Header.stx +51 -0
- package/resources/components/Marketing/Hero.stx +46 -0
- package/resources/components/Marketing/Layout.stx +26 -0
- package/resources/components/Marketing/NavLink.stx +13 -0
- package/resources/components/Marketing/Plan.stx +43 -0
- package/resources/components/Marketing/Pricing.stx +120 -0
- package/resources/components/Marketing/PrimaryFeatures.stx +80 -0
- package/resources/components/Marketing/PrimaryFeatures2.stx +98 -0
- package/resources/components/Marketing/SecondaryFeatures.stx +80 -0
- package/resources/components/Marketing/Testimonials.stx +120 -0
- package/resources/components/Pagination.stx +149 -0
- package/resources/components/Playground.stx +9 -0
- package/resources/components/README.md +87 -0
- package/resources/components/Storefront/AnnouncementBar.stx +17 -0
- package/resources/components/Storefront/CartDrawer.stx +227 -0
- package/resources/components/Storefront/CheckoutSteps.stx +50 -0
- package/resources/components/Storefront/Footer.stx +81 -0
- package/resources/components/Storefront/Header.stx +66 -0
- package/resources/components/Storefront/OrderSummary.stx +79 -0
- package/resources/components/Storefront/ProductCard.stx +63 -0
- package/resources/components/Storefront/ProductGallery.stx +88 -0
- package/resources/components/Storefront/QuantitySelector.stx +97 -0
- package/resources/components/index.ts +13 -0
- package/resources/emails/email-verification.stx +46 -0
- package/resources/emails/layouts/base.html +113 -0
- package/resources/emails/password-changed.stx +55 -0
- package/resources/emails/password-reset.stx +43 -0
- package/resources/emails/subscription-confirmation.stx +99 -0
- package/resources/emails/welcome.stx +48 -0
- package/resources/functions/README.md +28 -0
- package/resources/functions/counter.ts +13 -0
- package/resources/functions/dark.ts +4 -0
- package/resources/functions/dashboard/analytics.ts +238 -0
- package/resources/functions/dashboard/config-io.ts +316 -0
- package/resources/functions/dashboard/data.ts +375 -0
- package/resources/functions/dashboard/library.ts +250 -0
- package/resources/functions/dashboard/sidebar.ts +537 -0
- package/resources/functions/dashboard/system.ts +150 -0
- package/resources/layouts/403.stx +188 -0
- package/resources/layouts/404.stx +34 -0
- package/resources/layouts/README.md +14 -0
- package/resources/layouts/dashboard/default.stx +20 -0
- package/resources/layouts/dashboard/guest.stx +10 -0
- package/resources/layouts/default.stx +3 -0
- package/resources/layouts/maintenance.stx +11 -0
- package/resources/layouts/storefront.stx +73 -0
- package/resources/layouts/system-tray/default.stx +3 -0
- package/resources/modules/.gitkeep +0 -0
- package/resources/plugins/.gitkeep +0 -0
- package/resources/plugins/preloader.ts +308 -0
- package/resources/types/README.md +3 -0
- package/resources/views/cart.stx +149 -0
- package/resources/views/checkout/contact.stx +101 -0
- package/resources/views/checkout/payment.stx +114 -0
- package/resources/views/checkout/shipping.stx +120 -0
- package/resources/views/coming-soon.stx +9 -0
- package/resources/views/dashboard/custom-page.stx +45 -0
- package/resources/views/dashboard/index.stx +24 -0
- package/resources/views/emails/welcome.stx +0 -0
- package/resources/views/errors/tester.stx +26 -0
- package/resources/views/index.stx +2865 -0
- package/resources/views/orders/[id].stx +130 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
@import('../UI/Input', '../UI/Button')
|
|
2
|
+
|
|
3
|
+
<script server>
|
|
4
|
+
interface RegisterProps {
|
|
5
|
+
title?: string
|
|
6
|
+
subtitle?: string
|
|
7
|
+
name?: string
|
|
8
|
+
email?: string
|
|
9
|
+
password?: string
|
|
10
|
+
passwordConfirmation?: string
|
|
11
|
+
agreeToTerms?: boolean
|
|
12
|
+
isLoading?: boolean
|
|
13
|
+
error?: string
|
|
14
|
+
errors?: Record<string, any>
|
|
15
|
+
showLogin?: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const { title = 'Create an account', subtitle = 'Get started with your free account', name = '', email = '', password = '', passwordConfirmation = '', agreeToTerms = false, isLoading = false, error = '', errors = {}, showLogin = true } = defineProps<RegisterProps>()
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Register Component
|
|
22
|
+
* A clean, modern registration form for the Stacks Dashboard.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// Form state
|
|
26
|
+
// Password strength calculation
|
|
27
|
+
let passwordStrength = 0
|
|
28
|
+
let passwordStrengthLabel = ''
|
|
29
|
+
|
|
30
|
+
function computePasswordStrength(pw) {
|
|
31
|
+
let score = 0
|
|
32
|
+
if (pw.length >= 8) score++
|
|
33
|
+
if (pw.length >= 12) score++
|
|
34
|
+
if (/[A-Z]/.test(pw) && /[a-z]/.test(pw)) score++
|
|
35
|
+
if (/\d/.test(pw)) score++
|
|
36
|
+
if (/[^A-Za-z0-9]/.test(pw)) score++
|
|
37
|
+
|
|
38
|
+
// Map 0-5 score to 0-4 strength
|
|
39
|
+
passwordStrength = Math.min(4, score)
|
|
40
|
+
const labels = ['', 'Weak', 'Fair', 'Good', 'Strong']
|
|
41
|
+
passwordStrengthLabel = pw.length > 0 ? labels[passwordStrength] : ''
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Validation - validates individual fields on blur, full form on submit
|
|
45
|
+
function validateEmail() {
|
|
46
|
+
if (!email.trim()) {
|
|
47
|
+
errors.email = 'Email is required'
|
|
48
|
+
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
49
|
+
errors.email = 'Please enter a valid email'
|
|
50
|
+
} else {
|
|
51
|
+
errors.email = ''
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function validatePassword() {
|
|
56
|
+
if (!password) {
|
|
57
|
+
errors.password = 'Password is required'
|
|
58
|
+
} else if (password.length < 8) {
|
|
59
|
+
errors.password = 'Password must be at least 8 characters'
|
|
60
|
+
} else {
|
|
61
|
+
errors.password = ''
|
|
62
|
+
}
|
|
63
|
+
computePasswordStrength(password)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function validateConfirmation() {
|
|
67
|
+
if (passwordConfirmation && password !== passwordConfirmation) {
|
|
68
|
+
errors.passwordConfirmation = 'Passwords do not match'
|
|
69
|
+
} else {
|
|
70
|
+
errors.passwordConfirmation = ''
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function validateForm() {
|
|
75
|
+
const newErrors = {}
|
|
76
|
+
|
|
77
|
+
if (!name.trim()) {
|
|
78
|
+
newErrors.name = 'Name is required'
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!email.trim()) {
|
|
82
|
+
newErrors.email = 'Email is required'
|
|
83
|
+
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
84
|
+
newErrors.email = 'Please enter a valid email'
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (!password) {
|
|
88
|
+
newErrors.password = 'Password is required'
|
|
89
|
+
} else if (password.length < 8) {
|
|
90
|
+
newErrors.password = 'Password must be at least 8 characters'
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (password !== passwordConfirmation) {
|
|
94
|
+
newErrors.passwordConfirmation = 'Passwords do not match'
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!agreeToTerms) {
|
|
98
|
+
newErrors.terms = 'You must agree to the terms'
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
errors = newErrors
|
|
102
|
+
return Object.keys(newErrors).length === 0
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Emit submit event with credentials
|
|
106
|
+
function handleSubmit(event) {
|
|
107
|
+
event.preventDefault()
|
|
108
|
+
|
|
109
|
+
if (!validateForm()) {
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Emit the submit event - parent component handles the actual registration
|
|
114
|
+
$emit('submit', { name, email, password, password_confirmation: passwordConfirmation })
|
|
115
|
+
}
|
|
116
|
+
</script>
|
|
117
|
+
<div class="flex items-center justify-center px-4 py-12 min-h-screen">
|
|
118
|
+
<div class="max-w-sm w-full">
|
|
119
|
+
<!-- Logo/Brand -->
|
|
120
|
+
<div class="mb-8 text-center">
|
|
121
|
+
<div class="inline-flex items-center justify-center mb-4 h-12 w-12 bg-gradient-to-br from-blue-500 to-blue-600 rounded-xl shadow-blue-500/25 shadow-lg">
|
|
122
|
+
<svg class="h-7 w-7 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
123
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
|
|
124
|
+
</svg>
|
|
125
|
+
</div>
|
|
126
|
+
<h1 class="font-semibold text-2xl text-neutral-900 dark:text-white">
|
|
127
|
+
{{ title }}
|
|
128
|
+
</h1>
|
|
129
|
+
<p class="mt-2 text-neutral-500 text-sm dark:text-neutral-400">
|
|
130
|
+
{{ subtitle }}
|
|
131
|
+
</p>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
<!-- Register Form -->
|
|
135
|
+
<div class="p-6 bg-white dark:bg-neutral-900 border border-neutral-200/60 rounded-2xl dark:border-neutral-800 shadow-black/5 shadow-xl dark:shadow-black/20">
|
|
136
|
+
<!-- Error Message -->
|
|
137
|
+
@if(error)
|
|
138
|
+
<div class="mb-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 rounded-lg dark:border-red-800">
|
|
139
|
+
<div class="flex gap-2 items-center">
|
|
140
|
+
<div class="h-4 w-4 text-red-600 dark:text-red-400 i-hugeicons-alert-circle"></div>
|
|
141
|
+
<p class="text-red-600 text-sm dark:text-red-400">{{ error }}</p>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
@endif
|
|
145
|
+
|
|
146
|
+
<form @submit="handleSubmit">
|
|
147
|
+
<!-- Name Field -->
|
|
148
|
+
<div class="mb-4">
|
|
149
|
+
<Input
|
|
150
|
+
type="text"
|
|
151
|
+
label="Full name"
|
|
152
|
+
placeholder="John Doe"
|
|
153
|
+
:value="name"
|
|
154
|
+
@input="name = $event.target.value"
|
|
155
|
+
:error="errors.name"
|
|
156
|
+
required
|
|
157
|
+
:disabled="isLoading"
|
|
158
|
+
/>
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
<!-- Email Field -->
|
|
162
|
+
<div class="mb-4">
|
|
163
|
+
<Input
|
|
164
|
+
type="email"
|
|
165
|
+
label="Email address"
|
|
166
|
+
placeholder="you@example.com"
|
|
167
|
+
:value="email"
|
|
168
|
+
@input="email = $event.target.value"
|
|
169
|
+
@blur="validateEmail"
|
|
170
|
+
:error="errors.email"
|
|
171
|
+
required
|
|
172
|
+
:disabled="isLoading"
|
|
173
|
+
/>
|
|
174
|
+
</div>
|
|
175
|
+
|
|
176
|
+
<!-- Password Field -->
|
|
177
|
+
<div class="mb-4">
|
|
178
|
+
<Input
|
|
179
|
+
type="password"
|
|
180
|
+
label="Password"
|
|
181
|
+
placeholder="At least 8 characters"
|
|
182
|
+
:value="password"
|
|
183
|
+
@input="password = $event.target.value; validatePassword()"
|
|
184
|
+
@blur="validatePassword"
|
|
185
|
+
:error="errors.password"
|
|
186
|
+
required
|
|
187
|
+
:disabled="isLoading"
|
|
188
|
+
/>
|
|
189
|
+
<!-- Password Strength Indicator -->
|
|
190
|
+
@if(password.length > 0)
|
|
191
|
+
<div class="mt-2">
|
|
192
|
+
<div class="flex gap-1">
|
|
193
|
+
<div class="flex-1 h-1 rounded-full" :class="passwordStrength >= 1 ? (passwordStrength <= 1 ? 'bg-red-500' : passwordStrength === 2 ? 'bg-orange-500' : passwordStrength === 3 ? 'bg-yellow-500' : 'bg-green-500') : 'bg-neutral-200 dark:bg-neutral-700'"></div>
|
|
194
|
+
<div class="flex-1 h-1 rounded-full" :class="passwordStrength >= 2 ? (passwordStrength === 2 ? 'bg-orange-500' : passwordStrength === 3 ? 'bg-yellow-500' : 'bg-green-500') : 'bg-neutral-200 dark:bg-neutral-700'"></div>
|
|
195
|
+
<div class="flex-1 h-1 rounded-full" :class="passwordStrength >= 3 ? (passwordStrength === 3 ? 'bg-yellow-500' : 'bg-green-500') : 'bg-neutral-200 dark:bg-neutral-700'"></div>
|
|
196
|
+
<div class="flex-1 h-1 rounded-full" :class="passwordStrength >= 4 ? 'bg-green-500' : 'bg-neutral-200 dark:bg-neutral-700'"></div>
|
|
197
|
+
</div>
|
|
198
|
+
<p class="mt-1 text-xs" :class="passwordStrength <= 1 ? 'text-red-500' : passwordStrength === 2 ? 'text-orange-500' : passwordStrength === 3 ? 'text-yellow-600 dark:text-yellow-400' : 'text-green-500'">
|
|
199
|
+
{{ passwordStrengthLabel }}
|
|
200
|
+
</p>
|
|
201
|
+
</div>
|
|
202
|
+
@endif
|
|
203
|
+
</div>
|
|
204
|
+
|
|
205
|
+
<!-- Confirm Password Field -->
|
|
206
|
+
<div class="mb-4">
|
|
207
|
+
<Input
|
|
208
|
+
type="password"
|
|
209
|
+
label="Confirm password"
|
|
210
|
+
placeholder="Confirm your password"
|
|
211
|
+
:value="passwordConfirmation"
|
|
212
|
+
@input="passwordConfirmation = $event.target.value; validateConfirmation()"
|
|
213
|
+
:error="errors.passwordConfirmation"
|
|
214
|
+
required
|
|
215
|
+
:disabled="isLoading"
|
|
216
|
+
/>
|
|
217
|
+
</div>
|
|
218
|
+
|
|
219
|
+
<!-- Terms Checkbox -->
|
|
220
|
+
<div class="mb-6">
|
|
221
|
+
<label class="flex gap-2 items-start cursor-pointer">
|
|
222
|
+
<input
|
|
223
|
+
type="checkbox"
|
|
224
|
+
class="mt-0.5 h-4 w-4 text-blue-500 bg-white dark:bg-neutral-800 border-neutral-300 rounded dark:border-neutral-600 focus:ring-blue-500/40 focus:ring-offset-0"
|
|
225
|
+
:checked="agreeToTerms"
|
|
226
|
+
@change="agreeToTerms = $event.target.checked"
|
|
227
|
+
:disabled="isLoading"
|
|
228
|
+
/>
|
|
229
|
+
<span class="text-neutral-600 text-sm dark:text-neutral-400">
|
|
230
|
+
I agree to the
|
|
231
|
+
<a href="/terms" class="text-blue-600 dark:text-blue-400 hover:text-blue-500">Terms of Service</a>
|
|
232
|
+
and
|
|
233
|
+
<a href="/privacy" class="text-blue-600 dark:text-blue-400 hover:text-blue-500">Privacy Policy</a>
|
|
234
|
+
</span>
|
|
235
|
+
</label>
|
|
236
|
+
@if(errors.terms)
|
|
237
|
+
<p class="mt-1 text-red-600 text-sm dark:text-red-400">{{ errors.terms }}</p>
|
|
238
|
+
@endif
|
|
239
|
+
</div>
|
|
240
|
+
|
|
241
|
+
<!-- Submit Button -->
|
|
242
|
+
<Button
|
|
243
|
+
type="submit"
|
|
244
|
+
variant="primary"
|
|
245
|
+
size="lg"
|
|
246
|
+
fullWidth
|
|
247
|
+
:loading="isLoading"
|
|
248
|
+
:disabled="isLoading"
|
|
249
|
+
>
|
|
250
|
+
@if(isLoading)
|
|
251
|
+
Creating account...
|
|
252
|
+
@else
|
|
253
|
+
Create account
|
|
254
|
+
@endif
|
|
255
|
+
</Button>
|
|
256
|
+
</form>
|
|
257
|
+
|
|
258
|
+
<!-- Divider -->
|
|
259
|
+
<div class="relative my-6">
|
|
260
|
+
<div class="flex absolute inset-0 items-center">
|
|
261
|
+
<div class="w-full border-neutral-200 border-t dark:border-neutral-700"></div>
|
|
262
|
+
</div>
|
|
263
|
+
<div class="flex relative justify-center text-xs">
|
|
264
|
+
<span class="px-2 text-neutral-400 bg-white dark:bg-neutral-900">or continue with</span>
|
|
265
|
+
</div>
|
|
266
|
+
</div>
|
|
267
|
+
|
|
268
|
+
<!-- Social Login -->
|
|
269
|
+
<div class="grid gap-3 grid-cols-2">
|
|
270
|
+
<button
|
|
271
|
+
type="button"
|
|
272
|
+
class="flex gap-2 items-center justify-center px-4 py-2 font-medium text-neutral-700 text-sm dark:text-neutral-200 bg-white dark:bg-neutral-800 hover:bg-neutral-50 dark:hover:bg-neutral-700 border border-neutral-200 rounded-lg dark:border-neutral-700 transition-colors"
|
|
273
|
+
:disabled="isLoading"
|
|
274
|
+
>
|
|
275
|
+
<svg class="h-4 w-4" viewBox="0 0 24 24">
|
|
276
|
+
<path fill="currentColor" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
|
|
277
|
+
<path fill="currentColor" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
|
|
278
|
+
<path fill="currentColor" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
|
|
279
|
+
<path fill="currentColor" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
|
|
280
|
+
</svg>
|
|
281
|
+
Google
|
|
282
|
+
</button>
|
|
283
|
+
<button
|
|
284
|
+
type="button"
|
|
285
|
+
class="flex gap-2 items-center justify-center px-4 py-2 font-medium text-neutral-700 text-sm dark:text-neutral-200 bg-white dark:bg-neutral-800 hover:bg-neutral-50 dark:hover:bg-neutral-700 border border-neutral-200 rounded-lg dark:border-neutral-700 transition-colors"
|
|
286
|
+
:disabled="isLoading"
|
|
287
|
+
>
|
|
288
|
+
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="currentColor">
|
|
289
|
+
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
|
290
|
+
</svg>
|
|
291
|
+
GitHub
|
|
292
|
+
</button>
|
|
293
|
+
</div>
|
|
294
|
+
</div>
|
|
295
|
+
|
|
296
|
+
<!-- Login Link -->
|
|
297
|
+
@if(showLogin)
|
|
298
|
+
<p class="mt-6 text-center text-neutral-500 text-sm dark:text-neutral-400">
|
|
299
|
+
Already have an account?
|
|
300
|
+
<a href="/login" class="font-medium text-blue-600 dark:text-blue-400 hover:text-blue-500 dark:hover:text-blue-300">
|
|
301
|
+
Sign in
|
|
302
|
+
</a>
|
|
303
|
+
</p>
|
|
304
|
+
@endif
|
|
305
|
+
</div>
|
|
306
|
+
</div>
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
interface AvatarProps {
|
|
3
|
+
name?: string
|
|
4
|
+
size?: string
|
|
5
|
+
rounded?: string
|
|
6
|
+
status?: string
|
|
7
|
+
src?: string
|
|
8
|
+
alt?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { name = '', size = 'md', rounded = 'full', status, src, alt } = defineProps<AvatarProps>()
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Avatar Component
|
|
15
|
+
* Displays user avatar with optional status indicator
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const sizeClasses = {
|
|
19
|
+
xs: 'h-5 w-5 text-[10px]',
|
|
20
|
+
sm: 'h-7 w-7 text-[11px]',
|
|
21
|
+
md: 'h-8 w-8 text-[12px]',
|
|
22
|
+
lg: 'h-10 w-10 text-[13px]',
|
|
23
|
+
xl: 'h-12 w-12 text-[14px]',
|
|
24
|
+
'2xl': 'h-14 w-14 text-[16px]'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const radiusClasses = {
|
|
28
|
+
sm: 'rounded-md',
|
|
29
|
+
md: 'rounded-lg',
|
|
30
|
+
lg: 'rounded-xl',
|
|
31
|
+
full: 'rounded-full'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const statusColors = {
|
|
35
|
+
online: 'bg-green-500',
|
|
36
|
+
offline: 'bg-neutral-400',
|
|
37
|
+
away: 'bg-orange-500',
|
|
38
|
+
busy: 'bg-red-500'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const statusSizes = {
|
|
42
|
+
xs: 'h-1.5 w-1.5',
|
|
43
|
+
sm: 'h-2 w-2',
|
|
44
|
+
md: 'h-2 w-2',
|
|
45
|
+
lg: 'h-2.5 w-2.5',
|
|
46
|
+
xl: 'h-3 w-3',
|
|
47
|
+
'2xl': 'h-3.5 w-3.5'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Generate initials from name
|
|
51
|
+
function getInitials(fullName) {
|
|
52
|
+
if (!fullName) return ''
|
|
53
|
+
const parts = fullName.trim().split(/\s+/)
|
|
54
|
+
if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase()
|
|
55
|
+
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Background colors for initials (consistent based on name)
|
|
59
|
+
const bgColors = [
|
|
60
|
+
'bg-red-500/15 text-red-600 dark:bg-red-400/20 dark:text-red-400',
|
|
61
|
+
'bg-orange-500/15 text-orange-600 dark:bg-orange-400/20 dark:text-orange-400',
|
|
62
|
+
'bg-yellow-500/15 text-yellow-600 dark:bg-yellow-400/20 dark:text-yellow-400',
|
|
63
|
+
'bg-green-500/15 text-green-600 dark:bg-green-400/20 dark:text-green-400',
|
|
64
|
+
'bg-teal-500/15 text-teal-600 dark:bg-teal-400/20 dark:text-teal-400',
|
|
65
|
+
'bg-cyan-500/15 text-cyan-600 dark:bg-cyan-400/20 dark:text-cyan-400',
|
|
66
|
+
'bg-blue-500/15 text-blue-600 dark:bg-blue-400/20 dark:text-blue-400',
|
|
67
|
+
'bg-indigo-500/15 text-indigo-600 dark:bg-indigo-400/20 dark:text-indigo-400',
|
|
68
|
+
'bg-purple-500/15 text-purple-600 dark:bg-purple-400/20 dark:text-purple-400',
|
|
69
|
+
'bg-pink-500/15 text-pink-600 dark:bg-pink-400/20 dark:text-pink-400'
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
function getBgColorIndex(fullName) {
|
|
73
|
+
if (!fullName) return 0
|
|
74
|
+
let hash = 0
|
|
75
|
+
for (let i = 0; i < fullName.length; i++) {
|
|
76
|
+
hash = fullName.charCodeAt(i) + ((hash << 5) - hash)
|
|
77
|
+
}
|
|
78
|
+
return Math.abs(hash) % bgColors.length
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function getSizeClass() {
|
|
82
|
+
return sizeClasses[size || 'md']
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function getRadiusClass() {
|
|
86
|
+
return radiusClasses[rounded || 'full']
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function getStatusColor() {
|
|
90
|
+
return statusColors[status] || ''
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function getStatusSize() {
|
|
94
|
+
return statusSizes[size || 'md']
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function getBgColor() {
|
|
98
|
+
return name ? bgColors[getBgColorIndex(name)] : 'bg-black/[0.06] text-neutral-500 dark:bg-white/10 dark:text-neutral-400'
|
|
99
|
+
}
|
|
100
|
+
</script>
|
|
101
|
+
<div class="inline-flex relative flex-shrink-0">
|
|
102
|
+
@if(src)
|
|
103
|
+
<img
|
|
104
|
+
src="{{ src }}"
|
|
105
|
+
alt="{{ alt || name || 'Avatar' }}"
|
|
106
|
+
class="object-cover {{ getSizeClass() }} {{ getRadiusClass() }}"
|
|
107
|
+
>
|
|
108
|
+
@else
|
|
109
|
+
<div class="inline-flex items-center justify-center font-medium {{ getSizeClass() }} {{ getRadiusClass() }} {{ getBgColor() }}">
|
|
110
|
+
@if(name)
|
|
111
|
+
<span>{{ getInitials(name) }}</span>
|
|
112
|
+
@else
|
|
113
|
+
<svg class="h-1/2 w-1/2 text-neutral-400" fill="currentColor" viewBox="0 0 20 20">
|
|
114
|
+
<path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd"></path>
|
|
115
|
+
</svg>
|
|
116
|
+
@endif
|
|
117
|
+
</div>
|
|
118
|
+
@endif
|
|
119
|
+
|
|
120
|
+
@if(status)
|
|
121
|
+
<span class="absolute bottom-0 right-0 rounded-full ring-2 ring-white dark:ring-neutral-900 {{ getStatusColor() }} {{ getStatusSize() }}"></span>
|
|
122
|
+
@endif
|
|
123
|
+
</div>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
interface ActivePlanProps {
|
|
3
|
+
plan?: Record<string, any>
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const { plan = {} } = defineProps<ActivePlanProps>()
|
|
7
|
+
|
|
8
|
+
function convertUnixTimestampToDate(timestamp) {
|
|
9
|
+
if (!timestamp) return ''
|
|
10
|
+
const date = new Date(timestamp * 1000)
|
|
11
|
+
return date.toLocaleDateString()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const subscriptionType = plan.subscription?.type
|
|
15
|
+
? plan.subscription.type.charAt(0).toUpperCase() + plan.subscription.type.slice(1)
|
|
16
|
+
: ''
|
|
17
|
+
|
|
18
|
+
const nextPayment = convertUnixTimestampToDate(plan.providerSubscription?.current_period_end)
|
|
19
|
+
const unitPrice = plan.subscription?.unit_price ? (plan.subscription.unit_price / 100).toFixed(2) : '0.00'
|
|
20
|
+
</script>
|
|
21
|
+
<div class="w-full">
|
|
22
|
+
<h2 class="font-medium text-gray-900 text-lg">
|
|
23
|
+
Plan Details
|
|
24
|
+
</h2>
|
|
25
|
+
|
|
26
|
+
<div class="pt-8">
|
|
27
|
+
<p class="font-bold text-gray-700">
|
|
28
|
+
{{ subscriptionType }} Plan
|
|
29
|
+
</p>
|
|
30
|
+
|
|
31
|
+
<p class="pt-2 font-normal italic text-gray-500 text-sm">
|
|
32
|
+
{{ plan.subscription?.description || '' }}
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
<p class="pt-4 font-semibold text-gray-700 text-sm">
|
|
36
|
+
Next payment of ${{ unitPrice }} occurs on {{ nextPayment }}
|
|
37
|
+
</p>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<div class="flex mt-8">
|
|
41
|
+
<button
|
|
42
|
+
type="button"
|
|
43
|
+
class="px-2.5 py-1.5 font-semibold text-gray-900 text-sm bg-white hover:bg-gray-50 ring-1 ring-gray-300 ring-inset rounded-md shadow-sm"
|
|
44
|
+
data-action="cancel-plan"
|
|
45
|
+
>
|
|
46
|
+
Cancel Plan
|
|
47
|
+
</button>
|
|
48
|
+
|
|
49
|
+
<button
|
|
50
|
+
type="button"
|
|
51
|
+
class="ml-4 px-2.5 py-1.5 font-semibold text-sm text-white bg-blue-600 hover:bg-neutral-500 rounded-md focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2 shadow-sm"
|
|
52
|
+
data-action="change-plan"
|
|
53
|
+
>
|
|
54
|
+
Change Plan
|
|
55
|
+
</button>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
interface CardBrandsProps {
|
|
3
|
+
brand?: string
|
|
4
|
+
width?: number
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const { brand = '', width = 4 } = defineProps<CardBrandsProps>()
|
|
8
|
+
|
|
9
|
+
function getLogoSrc(cardBrand) {
|
|
10
|
+
if (!cardBrand) return ''
|
|
11
|
+
|
|
12
|
+
switch (cardBrand.toLowerCase()) {
|
|
13
|
+
case 'visa':
|
|
14
|
+
return '/images/logos/visa.png'
|
|
15
|
+
case 'mastercard':
|
|
16
|
+
case 'mc':
|
|
17
|
+
return '/images/logos/mastercard.svg'
|
|
18
|
+
case 'jcb':
|
|
19
|
+
return '/images/logos/jcb.svg'
|
|
20
|
+
case 'amex':
|
|
21
|
+
case 'american express':
|
|
22
|
+
return '/images/logos/amex.jpg'
|
|
23
|
+
default:
|
|
24
|
+
return '/images/logos/default-card.svg'
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const logoSrc = getLogoSrc(brand)
|
|
29
|
+
</script>
|
|
30
|
+
<div style="width: {{ width }}rem">
|
|
31
|
+
<img src="{{ logoSrc }}" alt="{{ brand }} Logo">
|
|
32
|
+
</div>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
interface CardFormProps {
|
|
3
|
+
clientSecret?: string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const { clientSecret = '' } = defineProps<CardFormProps>()
|
|
7
|
+
</script>
|
|
8
|
+
<div>
|
|
9
|
+
<form
|
|
10
|
+
id="card-form"
|
|
11
|
+
class="mt-8 p-8 border border-gray-200"
|
|
12
|
+
>
|
|
13
|
+
<div id="link-authentication-element"></div>
|
|
14
|
+
<div id="card-element"></div>
|
|
15
|
+
|
|
16
|
+
<div class="flex mt-6 space-x-2">
|
|
17
|
+
<button
|
|
18
|
+
type="button"
|
|
19
|
+
class="px-2 py-1.5 w-full font-semibold text-sm text-white bg-indigo-600 hover:bg-indigo-500 rounded focus-visible:outline focus-visible:outline-2 focus-visible:outline-indigo-600 focus-visible:outline-offset-2 shadow-sm"
|
|
20
|
+
data-action="save-payment-method"
|
|
21
|
+
>
|
|
22
|
+
Save Payment Method
|
|
23
|
+
</button>
|
|
24
|
+
|
|
25
|
+
<button
|
|
26
|
+
type="button"
|
|
27
|
+
class="px-2 py-1.5 w-full font-semibold text-gray-900 text-sm bg-white hover:bg-gray-50 ring-1 ring-gray-300 ring-inset rounded shadow-sm"
|
|
28
|
+
data-action="cancel"
|
|
29
|
+
>
|
|
30
|
+
Cancel
|
|
31
|
+
</button>
|
|
32
|
+
</div>
|
|
33
|
+
</form>
|
|
34
|
+
</div>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
interface OneTimePaymentProps {
|
|
3
|
+
product?: Record<string, any>
|
|
4
|
+
paymentIntent?: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const { product = {}, paymentIntent = '' } = defineProps<OneTimePaymentProps>()
|
|
8
|
+
|
|
9
|
+
const unitPrice = product.unit_price ? `${(product.unit_price / 100).toFixed(2)}` : '$0.00'
|
|
10
|
+
</script>
|
|
11
|
+
@if(product.name)
|
|
12
|
+
<div class="flex p-4 space-x-2 border border-gray-200 rounded-md">
|
|
13
|
+
<ul role="list" class="w-1/3 font-medium text-gray-900 text-sm divide-gray-200 divide-y">
|
|
14
|
+
<li class="flex items-ce space-x-4">
|
|
15
|
+
<img src="https://tailwindui.com/plus/img/ecommerce-images/checkout-page-04-product-01.jpg" alt="Moss green canvas compact backpack with double top zipper, zipper front pouch, and matching carry handle and backpack straps." class="object-cover flex-none size-20 border rounded-md">
|
|
16
|
+
<div class="flex-auto mt-2 space-y-1">
|
|
17
|
+
<h3>{{ product.name }}</h3>
|
|
18
|
+
<p class="flex-none font-medium text-sm">
|
|
19
|
+
{{ unitPrice }}
|
|
20
|
+
</p>
|
|
21
|
+
</div>
|
|
22
|
+
</li>
|
|
23
|
+
</ul>
|
|
24
|
+
<div class="w-2/3">
|
|
25
|
+
<slot name="paymentForm" />
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
@endif
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
interface PaymentFormProps {
|
|
3
|
+
productId?: number
|
|
4
|
+
price?: string
|
|
5
|
+
paymentIntent?: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const { productId = 1, price = '$0.00', paymentIntent = '' } = defineProps<PaymentFormProps>()
|
|
9
|
+
</script>
|
|
10
|
+
<div>
|
|
11
|
+
<form id="payment-form">
|
|
12
|
+
<div id="link-authentication-element"></div>
|
|
13
|
+
<div id="payment-element"></div>
|
|
14
|
+
|
|
15
|
+
<div class="flex mt-6 space-x-2">
|
|
16
|
+
<button
|
|
17
|
+
type="button"
|
|
18
|
+
class="px-2 py-1.5 w-full font-semibold text-sm text-white bg-indigo-600 hover:bg-indigo-500 rounded focus-visible:outline focus-visible:outline-2 focus-visible:outline-indigo-600 focus-visible:outline-offset-2 shadow-sm"
|
|
19
|
+
data-action="pay"
|
|
20
|
+
>
|
|
21
|
+
Pay {{ price }}
|
|
22
|
+
</button>
|
|
23
|
+
|
|
24
|
+
<button
|
|
25
|
+
type="button"
|
|
26
|
+
class="px-2 py-1.5 w-full font-semibold text-gray-900 text-sm bg-white hover:bg-gray-50 ring-1 ring-gray-300 ring-inset rounded shadow-sm"
|
|
27
|
+
data-action="cancel"
|
|
28
|
+
>
|
|
29
|
+
Cancel
|
|
30
|
+
</button>
|
|
31
|
+
</div>
|
|
32
|
+
</form>
|
|
33
|
+
</div>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
interface PaymentMethodProps {
|
|
3
|
+
defaultPaymentMethod?: any
|
|
4
|
+
paymentMethods?: any[]
|
|
5
|
+
loading?: boolean
|
|
6
|
+
showCardForm?: boolean
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const { defaultPaymentMethod = null, paymentMethods = [], loading = false, showCardForm = false } = defineProps<PaymentMethodProps>()
|
|
10
|
+
</script>
|
|
11
|
+
<div class="mt-16 px-8 py-6 w-2/3 bg-white ring-1 ring-black ring-opacity-5 sm:rounded-lg shadow">
|
|
12
|
+
<h2 class="font-medium text-gray-900 text-lg">
|
|
13
|
+
Payment Info
|
|
14
|
+
</h2>
|
|
15
|
+
|
|
16
|
+
@if(loading)
|
|
17
|
+
<div class="mt-8">
|
|
18
|
+
<slot name="loading" />
|
|
19
|
+
</div>
|
|
20
|
+
@else
|
|
21
|
+
@if(defaultPaymentMethod)
|
|
22
|
+
<div class="col-span-1 mt-8 bg-white border divide-gray-200 divide-y rounded-lg shadow">
|
|
23
|
+
<div class="p-3 w-full">
|
|
24
|
+
<div class="flex items-center justify-between">
|
|
25
|
+
<div class="flex items-center space-x-4">
|
|
26
|
+
<slot name="cardBrand" />
|
|
27
|
+
|
|
28
|
+
<h2 class="text-gray-600 text-sm">
|
|
29
|
+
{{ defaultPaymentMethod.brand }} •••• {{ defaultPaymentMethod.last_four }}
|
|
30
|
+
<span class="inline-flex items-center ml-4 px-2 py-1 font-medium text-indigo-700 text-xs bg-indigo-50 ring-1 ring-indigo-700/10 ring-inset rounded-md">Default</span>
|
|
31
|
+
<br>
|
|
32
|
+
<span class="italic text-gray-500 text-xs">Expires {{ defaultPaymentMethod.exp_month }} / {{ defaultPaymentMethod.exp_year }}</span>
|
|
33
|
+
</h2>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
@else
|
|
39
|
+
<div class="col-span-1 mt-8 bg-white border divide-gray-200 divide-y rounded-lg shadow">
|
|
40
|
+
<div class="px-4 py-5 w-full">
|
|
41
|
+
<h2 class="text-center text-gray-600 text-sm">
|
|
42
|
+
You haven't added any payment methods yet.
|
|
43
|
+
</h2>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
@endif
|
|
47
|
+
@endif
|
|
48
|
+
|
|
49
|
+
<slot name="paymentMethodList" />
|
|
50
|
+
|
|
51
|
+
@if(showCardForm)
|
|
52
|
+
<slot name="cardForm" />
|
|
53
|
+
@endif
|
|
54
|
+
|
|
55
|
+
@if(!showCardForm)
|
|
56
|
+
<div class="flex justify-end mt-8">
|
|
57
|
+
<button
|
|
58
|
+
type="button"
|
|
59
|
+
class="px-3.5 py-2.5 font-semibold text-sm text-white bg-blue-600 hover:bg-neutral-500 rounded-md focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2 shadow-sm"
|
|
60
|
+
data-action="add-payment-method"
|
|
61
|
+
>
|
|
62
|
+
Add Payment Method
|
|
63
|
+
</button>
|
|
64
|
+
</div>
|
|
65
|
+
@endif
|
|
66
|
+
</div>
|