robodev 0.23.0 → 0.25.0
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/package.json +1 -1
- package/src/emit-starter.test.ts +36 -0
- package/templates/auth-chat/package.json +1 -1
- package/templates/backend/package.json +1 -1
- package/templates/catalog.json +5 -0
- package/templates/empty/package.json +1 -1
- package/templates/marketplace/.config/local.spa.template.yml +27 -0
- package/templates/marketplace/.oxlint-base.json +29 -0
- package/templates/marketplace/.oxlintrc.json +78 -0
- package/templates/marketplace/.rulesync/rules/frontend-api-boundary.md +36 -0
- package/templates/marketplace/.rulesync/rules/frontend-component-structure.md +38 -0
- package/templates/marketplace/.rulesync/rules/frontend-forms.md +32 -0
- package/templates/marketplace/.rulesync/rules/frontend-notifications.md +24 -0
- package/templates/marketplace/.rulesync/rules/frontend-povio-components.md +42 -0
- package/templates/marketplace/.rulesync/rules/frontend-povio-ui.md +45 -0
- package/templates/marketplace/.rulesync/rules/frontend-query-autocomplete.md +29 -0
- package/templates/marketplace/.rulesync/rules/frontend-tables-and-lists.md +34 -0
- package/templates/marketplace/.rulesync/rules/frontend-translations.md +26 -0
- package/templates/marketplace/.rulesync/rules/project-overview.md +32 -0
- package/templates/marketplace/.rulesync/rules/robodev-api.md +30 -0
- package/templates/marketplace/.rulesync/rules/robodev-auth.md +40 -0
- package/templates/marketplace/.rulesync/rules/robodev-database.md +22 -0
- package/templates/marketplace/.rulesync/rules/role-based-app-structure.md +36 -0
- package/templates/marketplace/.rulesync/skills/media-feature/SKILL.md +21 -0
- package/templates/marketplace/.rulesync/skills/povio-ui-styling/SKILL.md +208 -0
- package/templates/marketplace/.rulesync/skills/povio-ui-styling/agents/openai.yaml +4 -0
- package/templates/marketplace/.rulesync/skills/robodev-api-route/SKILL.md +13 -0
- package/templates/marketplace/.rulesync/skills/robodev-table/SKILL.md +12 -0
- package/templates/marketplace/README.md +40 -0
- package/templates/marketplace/api/_lib.seed.test.ts +10 -0
- package/templates/marketplace/api/_lib.ts +734 -0
- package/templates/marketplace/api/cart/[id].ts +51 -0
- package/templates/marketplace/api/cart.ts +70 -0
- package/templates/marketplace/api/categories.ts +11 -0
- package/templates/marketplace/api/checkout.ts +157 -0
- package/templates/marketplace/api/health.ts +7 -0
- package/templates/marketplace/api/listings/[id].ts +101 -0
- package/templates/marketplace/api/listings/paginate.ts +29 -0
- package/templates/marketplace/api/listings.ts +90 -0
- package/templates/marketplace/api/me.ts +14 -0
- package/templates/marketplace/api/orders/[id]/complete.ts +27 -0
- package/templates/marketplace/api/orders/[id]/ship.ts +24 -0
- package/templates/marketplace/api/orders/[id].ts +15 -0
- package/templates/marketplace/api/purchases.ts +19 -0
- package/templates/marketplace/api/reviews.ts +58 -0
- package/templates/marketplace/api/sales.ts +19 -0
- package/templates/marketplace/api/watches/[listingId].ts +18 -0
- package/templates/marketplace/api/watches.ts +51 -0
- package/templates/marketplace/apps/fe/index.html +24 -0
- package/templates/marketplace/apps/fe/openapi-codegen.config.ts +72 -0
- package/templates/marketplace/apps/fe/package.json +84 -0
- package/templates/marketplace/apps/fe/public/apple-touch-icon.png +0 -0
- package/templates/marketplace/apps/fe/public/favicon-96x96.png +0 -0
- package/templates/marketplace/apps/fe/public/favicon.ico +0 -0
- package/templates/marketplace/apps/fe/public/favicon.svg +3 -0
- package/templates/marketplace/apps/fe/public/site.webmanifest +21 -0
- package/templates/marketplace/apps/fe/public/web-app-manifest-192x192.png +0 -0
- package/templates/marketplace/apps/fe/public/web-app-manifest-512x512.png +0 -0
- package/templates/marketplace/apps/fe/src/assets/fonts/GeneralSans-Bold.otf +0 -0
- package/templates/marketplace/apps/fe/src/assets/fonts/GeneralSans-Medium.otf +0 -0
- package/templates/marketplace/apps/fe/src/assets/fonts/GeneralSans-Regular.otf +0 -0
- package/templates/marketplace/apps/fe/src/assets/fonts/GeneralSans-Semibold.otf +0 -0
- package/templates/marketplace/apps/fe/src/assets/locales/en/translation.json +336 -0
- package/templates/marketplace/apps/fe/src/assets/locales/sl/translation.json +336 -0
- package/templates/marketplace/apps/fe/src/clients/app-rest-client.ts +15 -0
- package/templates/marketplace/apps/fe/src/clients/auth-token-store.ts +101 -0
- package/templates/marketplace/apps/fe/src/clients/rest/app-error-handler.ts +31 -0
- package/templates/marketplace/apps/fe/src/clients/rest/interceptors/authorization-header.interceptor.ts +15 -0
- package/templates/marketplace/apps/fe/src/clients/rest/interceptors/refresh-token.interceptor.ts +37 -0
- package/templates/marketplace/apps/fe/src/clients/rest/interceptors/response.interceptor.ts +17 -0
- package/templates/marketplace/apps/fe/src/components/404.tsx +18 -0
- package/templates/marketplace/apps/fe/src/components/features/auth/AuthBrandPanel.tsx +60 -0
- package/templates/marketplace/apps/fe/src/components/features/auth/AuthLayout.tsx +23 -0
- package/templates/marketplace/apps/fe/src/components/features/auth/LoginPage.tsx +111 -0
- package/templates/marketplace/apps/fe/src/components/features/auth/RegisterPage.tsx +143 -0
- package/templates/marketplace/apps/fe/src/components/features/marketplace/BrowsePage.tsx +76 -0
- package/templates/marketplace/apps/fe/src/components/features/marketplace/CartPage.tsx +88 -0
- package/templates/marketplace/apps/fe/src/components/features/marketplace/CheckoutPage.tsx +193 -0
- package/templates/marketplace/apps/fe/src/components/features/marketplace/ListingCard.tsx +50 -0
- package/templates/marketplace/apps/fe/src/components/features/marketplace/ListingDetailsPage.tsx +194 -0
- package/templates/marketplace/apps/fe/src/components/features/marketplace/ListingForm.tsx +278 -0
- package/templates/marketplace/apps/fe/src/components/features/marketplace/ListingFormPage.tsx +27 -0
- package/templates/marketplace/apps/fe/src/components/features/marketplace/ListingGallery.tsx +54 -0
- package/templates/marketplace/apps/fe/src/components/features/marketplace/MyListingsPage.tsx +137 -0
- package/templates/marketplace/apps/fe/src/components/features/marketplace/OrderStatusTag.tsx +24 -0
- package/templates/marketplace/apps/fe/src/components/features/marketplace/OrderSummaryCard.tsx +39 -0
- package/templates/marketplace/apps/fe/src/components/features/marketplace/OrdersPage.tsx +236 -0
- package/templates/marketplace/apps/fe/src/components/features/marketplace/WatchlistPage.tsx +56 -0
- package/templates/marketplace/apps/fe/src/components/features/profile/ProfilePage.tsx +96 -0
- package/templates/marketplace/apps/fe/src/components/googleAnalytics/GoogleAnalytics.tsx +35 -0
- package/templates/marketplace/apps/fe/src/components/layout/AppLayout.tsx +19 -0
- package/templates/marketplace/apps/fe/src/components/layout/app-header/AppHeader.tsx +95 -0
- package/templates/marketplace/apps/fe/src/components/layout/app-header/MobileNavigation.tsx +55 -0
- package/templates/marketplace/apps/fe/src/components/layout/app-header/NavLink.tsx +29 -0
- package/templates/marketplace/apps/fe/src/components/shared/branding/BrandLogo.tsx +13 -0
- package/templates/marketplace/apps/fe/src/components/shared/error/ErrorFallback.tsx +43 -0
- package/templates/marketplace/apps/fe/src/components/shared/error/ErrorText.tsx +20 -0
- package/templates/marketplace/apps/fe/src/components/shared/error/NotFound.tsx +36 -0
- package/templates/marketplace/apps/fe/src/components/shared/forms/RequiredLabel.tsx +21 -0
- package/templates/marketplace/apps/fe/src/components/shared/forms/RowInputWrapper.tsx +50 -0
- package/templates/marketplace/apps/fe/src/components/shared/head/AppHead.tsx +32 -0
- package/templates/marketplace/apps/fe/src/components/shared/head/DefaultAppHead.tsx +34 -0
- package/templates/marketplace/apps/fe/src/components/shared/layout/LoadingState.tsx +9 -0
- package/templates/marketplace/apps/fe/src/components/shared/layout/ThinPageWrapper.tsx +5 -0
- package/templates/marketplace/apps/fe/src/components/shared/page/PageHeader.tsx +69 -0
- package/templates/marketplace/apps/fe/src/components/shared/ui/Card.tsx +60 -0
- package/templates/marketplace/apps/fe/src/components/shared/ui/GoogleLoginButton.tsx +19 -0
- package/templates/marketplace/apps/fe/src/components/shared/ui/RequiredLabel.tsx +22 -0
- package/templates/marketplace/apps/fe/src/components/shared/ui/TableActions.tsx +22 -0
- package/templates/marketplace/apps/fe/src/config/app.config.ts +35 -0
- package/templates/marketplace/apps/fe/src/config/i18n.ts +43 -0
- package/templates/marketplace/apps/fe/src/config/inits/a11y.ts +14 -0
- package/templates/marketplace/apps/fe/src/config/inits/logger.ts +7 -0
- package/templates/marketplace/apps/fe/src/config/inits/sentry.ts +21 -0
- package/templates/marketplace/apps/fe/src/config/jwt.config.ts +2 -0
- package/templates/marketplace/apps/fe/src/config/query.config.ts +20 -0
- package/templates/marketplace/apps/fe/src/hooks/useAuth.ts +5 -0
- package/templates/marketplace/apps/fe/src/main.tsx +52 -0
- package/templates/marketplace/apps/fe/src/pages/(guest)/login.tsx +23 -0
- package/templates/marketplace/apps/fe/src/pages/(guest)/register.tsx +23 -0
- package/templates/marketplace/apps/fe/src/pages/(guest)/route.tsx +18 -0
- package/templates/marketplace/apps/fe/src/pages/(private)/cart.tsx +22 -0
- package/templates/marketplace/apps/fe/src/pages/(private)/checkout.tsx +22 -0
- package/templates/marketplace/apps/fe/src/pages/(private)/index.tsx +22 -0
- package/templates/marketplace/apps/fe/src/pages/(private)/listings/$id/index.tsx +37 -0
- package/templates/marketplace/apps/fe/src/pages/(private)/my-listings.tsx +32 -0
- package/templates/marketplace/apps/fe/src/pages/(private)/orders/$id.tsx +40 -0
- package/templates/marketplace/apps/fe/src/pages/(private)/orders/index.tsx +22 -0
- package/templates/marketplace/apps/fe/src/pages/(private)/profile.tsx +23 -0
- package/templates/marketplace/apps/fe/src/pages/(private)/route.tsx +18 -0
- package/templates/marketplace/apps/fe/src/pages/(private)/sales.tsx +22 -0
- package/templates/marketplace/apps/fe/src/pages/(private)/sell/$id.tsx +44 -0
- package/templates/marketplace/apps/fe/src/pages/(private)/sell/index.tsx +15 -0
- package/templates/marketplace/apps/fe/src/pages/(private)/watchlist.tsx +22 -0
- package/templates/marketplace/apps/fe/src/pages/(public)/auth.tsx +37 -0
- package/templates/marketplace/apps/fe/src/pages/(public)/route.tsx +9 -0
- package/templates/marketplace/apps/fe/src/pages/__root.tsx +164 -0
- package/templates/marketplace/apps/fe/src/providers/AppErrorBoundary.tsx +10 -0
- package/templates/marketplace/apps/fe/src/providers/OpenApiRuntimeProvider.tsx +31 -0
- package/templates/marketplace/apps/fe/src/providers/index.tsx +44 -0
- package/templates/marketplace/apps/fe/src/providers/jwt.provider.tsx +95 -0
- package/templates/marketplace/apps/fe/src/routeTree.gen.ts +435 -0
- package/templates/marketplace/apps/fe/src/styles/base.css +103 -0
- package/templates/marketplace/apps/fe/src/styles/fonts/fonts.tsx +10 -0
- package/templates/marketplace/apps/fe/src/styles/fonts/general-sans.css +31 -0
- package/templates/marketplace/apps/fe/src/styles/globals.css +28 -0
- package/templates/marketplace/apps/fe/src/styles/overrides/defaults/button.override.ts +536 -0
- package/templates/marketplace/apps/fe/src/styles/overrides/defaults/checkbox.override.ts +71 -0
- package/templates/marketplace/apps/fe/src/styles/overrides/defaults/input.override.ts +252 -0
- package/templates/marketplace/apps/fe/src/styles/overrides/defaults/label.override.ts +91 -0
- package/templates/marketplace/apps/fe/src/styles/overrides/defaults/modal.override.ts +57 -0
- package/templates/marketplace/apps/fe/src/styles/overrides/defaults/radio.override.ts +46 -0
- package/templates/marketplace/apps/fe/src/styles/overrides/defaults/table.override.ts +104 -0
- package/templates/marketplace/apps/fe/src/styles/overrides/defaults/tag.override.ts +66 -0
- package/templates/marketplace/apps/fe/src/styles/overrides/defaults/typography.override.ts +115 -0
- package/templates/marketplace/apps/fe/src/styles/overrides/outline.clsx.ts +10 -0
- package/templates/marketplace/apps/fe/src/styles/overrides/uiOverrides.override.ts +60 -0
- package/templates/marketplace/apps/fe/src/styles/theme.css +2177 -0
- package/templates/marketplace/apps/fe/src/types/i18next.d.ts +12 -0
- package/templates/marketplace/apps/fe/src/types/table.d.ts +17 -0
- package/templates/marketplace/apps/fe/src/types/ui.d.ts +26 -0
- package/templates/marketplace/apps/fe/src/types/vite-env.d.ts +20 -0
- package/templates/marketplace/apps/fe/src/utils/date.utils.ts +17 -0
- package/templates/marketplace/apps/fe/src/utils/image-fallback.ts +9 -0
- package/templates/marketplace/apps/fe/src/utils/listing-form.test.ts +69 -0
- package/templates/marketplace/apps/fe/src/utils/listing-form.ts +77 -0
- package/templates/marketplace/apps/fe/src/utils/listing-submit.ts +29 -0
- package/templates/marketplace/apps/fe/src/utils/number.utils.ts +12 -0
- package/templates/marketplace/apps/fe/src/utils/string.utils.ts +5 -0
- package/templates/marketplace/apps/fe/src/vite-env.d.ts +1 -0
- package/templates/marketplace/apps/fe/tsconfig.app.json +32 -0
- package/templates/marketplace/apps/fe/tsconfig.json +9 -0
- package/templates/marketplace/apps/fe/tsconfig.node.json +31 -0
- package/templates/marketplace/apps/fe/vite.config.ts +125 -0
- package/templates/marketplace/database.ts +154 -0
- package/templates/marketplace/openapi.json +2303 -0
- package/templates/marketplace/oxfmt.config.js +23 -0
- package/templates/marketplace/package.json +18 -0
- package/templates/marketplace/rulesync.jsonc +18 -0
- package/templates/marketplace/tsconfig.json +11 -0
- package/templates/space/package.json +1 -1
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
{
|
|
2
|
+
"appName": "Marketplace",
|
|
3
|
+
"appDescription": "Tržnica za takojšnji nakup blaga",
|
|
4
|
+
"shared": {
|
|
5
|
+
"notFound": {
|
|
6
|
+
"head": {
|
|
7
|
+
"title": "Stran ni bila najdena",
|
|
8
|
+
"description": "Stran, ki jo iščete, ne obstaja."
|
|
9
|
+
},
|
|
10
|
+
"heading": "Stran ni bila najdena",
|
|
11
|
+
"subheading": "Stran, ki jo iščete, ne obstaja.",
|
|
12
|
+
"homeBtn": "Na domačo stran"
|
|
13
|
+
},
|
|
14
|
+
"errorFallback": {
|
|
15
|
+
"heading": "Nekaj je šlo narobe",
|
|
16
|
+
"subheading": "Napaka: {{error}}",
|
|
17
|
+
"retryBtn": "Poskusi znova"
|
|
18
|
+
},
|
|
19
|
+
"apiErrors": {
|
|
20
|
+
"requestFailed": "Zahteva ni uspela: {{error}}",
|
|
21
|
+
"unknown": "Prišlo je do neznane napake."
|
|
22
|
+
},
|
|
23
|
+
"seedData": {
|
|
24
|
+
"actionButton": "Ponastavi začetne podatke",
|
|
25
|
+
"confirmation": {
|
|
26
|
+
"heading": "Ponastaviti začetne podatke?",
|
|
27
|
+
"description": "Vsi lokalni podatki bodo ponastavljeni na začetno stanje.",
|
|
28
|
+
"confirm": "Ponastavi",
|
|
29
|
+
"cancel": "Prekliči"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"actions": {
|
|
33
|
+
"back": "Nazaj"
|
|
34
|
+
},
|
|
35
|
+
"fakeMailbox": {
|
|
36
|
+
"title": "Lažni poštni predal",
|
|
37
|
+
"open": "Odpri lažni poštni predal",
|
|
38
|
+
"close": "Zapri lažni poštni predal",
|
|
39
|
+
"empty": "Ni prejetih e-poštnih sporočil.",
|
|
40
|
+
"from": "Od",
|
|
41
|
+
"to": "Za",
|
|
42
|
+
"cc": "Kp",
|
|
43
|
+
"bcc": "Skp",
|
|
44
|
+
"replyTo": "Odgovori na",
|
|
45
|
+
"openPopup": "Odpri pojavno okno",
|
|
46
|
+
"popupBlocked": {
|
|
47
|
+
"heading": "Pojavno okno e-pošte je blokirano",
|
|
48
|
+
"description": "Brskalnik je blokiral samodejno okno e-pošte. Dovolite pojavna okna za to stran ali sporočilo odprite zdaj.",
|
|
49
|
+
"open": "Odpri e-pošto",
|
|
50
|
+
"cancel": "Pusti neprebrano"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"auth": {
|
|
55
|
+
"wrapper": {
|
|
56
|
+
"title": "Administrativni portal",
|
|
57
|
+
"description": "Tiny",
|
|
58
|
+
"watermark": "© {{year}} Tiny • Razvija in vzdržuje Povio"
|
|
59
|
+
},
|
|
60
|
+
"shared": {
|
|
61
|
+
"errors": {
|
|
62
|
+
"invalidCredentials": "Neveljaven e-poštni naslov ali geslo.",
|
|
63
|
+
"userAlreadyExists": "Račun s tem e-poštnim naslovom že obstaja.",
|
|
64
|
+
"identityNotFound": "Tega računa ni bilo mogoče najti.",
|
|
65
|
+
"notConfirmed": "Ta račun še ni potrjen."
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"login": {
|
|
69
|
+
"head": {
|
|
70
|
+
"title": "Prijava",
|
|
71
|
+
"description": "Prijavite se v svoj račun"
|
|
72
|
+
},
|
|
73
|
+
"form": {
|
|
74
|
+
"title": "Prijava",
|
|
75
|
+
"email": "E-pošta",
|
|
76
|
+
"emailPlaceholder": "Vnesite svoj e-poštni naslov",
|
|
77
|
+
"password": "Geslo",
|
|
78
|
+
"passwordPlaceholder": "Vnesite svoje geslo",
|
|
79
|
+
"submit": "Prijava",
|
|
80
|
+
"submitLoading": "Prijavljanje...",
|
|
81
|
+
"demoLogin": "Prijava kot demo uporabnik",
|
|
82
|
+
"noAccount": "Nimate računa?",
|
|
83
|
+
"registerLink": "Registracija",
|
|
84
|
+
"loginFailed": "Prijava ni uspela",
|
|
85
|
+
"resetSeedData": "Ponastavi začetne podatke"
|
|
86
|
+
},
|
|
87
|
+
"confirmations": {
|
|
88
|
+
"resetSeed": {
|
|
89
|
+
"heading": "Ponastaviti začetne podatke?",
|
|
90
|
+
"description": "Vsi lokalni podatki bodo ponastavljeni na začetno stanje.",
|
|
91
|
+
"confirm": "Ponastavi",
|
|
92
|
+
"cancel": "Prekliči"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"register": {
|
|
97
|
+
"head": {
|
|
98
|
+
"title": "Registracija",
|
|
99
|
+
"description": "Ustvarite nov račun"
|
|
100
|
+
},
|
|
101
|
+
"form": {
|
|
102
|
+
"title": "Registracija",
|
|
103
|
+
"description": "Ustvarite nov račun",
|
|
104
|
+
"email": "E-pošta",
|
|
105
|
+
"emailPlaceholder": "Vnesite svoj e-poštni naslov",
|
|
106
|
+
"name": "Ime",
|
|
107
|
+
"namePlaceholder": "Vnesite svoje ime",
|
|
108
|
+
"password": "Geslo",
|
|
109
|
+
"passwordPlaceholder": "Vnesite svoje geslo",
|
|
110
|
+
"confirmPassword": "Potrdite geslo",
|
|
111
|
+
"confirmPasswordPlaceholder": "Potrdite svoje geslo",
|
|
112
|
+
"confirmPasswordRequired": "Potrditev gesla je obvezna",
|
|
113
|
+
"passwordsDoNotMatch": "Gesli se ne ujemata",
|
|
114
|
+
"passwordRequirements": "Geslo mora vsebovati vsaj 12 znakov.",
|
|
115
|
+
"submit": "Registriraj se",
|
|
116
|
+
"registrationFailed": "Registracija ni uspela",
|
|
117
|
+
"hasAccount": "Že imate račun?",
|
|
118
|
+
"loginLink": "Prijava"
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"setPassword": {
|
|
122
|
+
"form": {
|
|
123
|
+
"title": "Nastavite svoje geslo",
|
|
124
|
+
"welcome": "Dobrodošli, {{firstName}} {{lastName}}. Nastavite geslo, da dokončate nastavitev računa.",
|
|
125
|
+
"tokenNote": "Vnesite povabilni žeton, ki ste ga prejeli po e-pošti.",
|
|
126
|
+
"token": "Povabilni žeton",
|
|
127
|
+
"tokenPlaceholder": "Vnesite svoj povabilni žeton",
|
|
128
|
+
"tokenChecking": "Preverjanje žetona...",
|
|
129
|
+
"tokenError": "{{error}}",
|
|
130
|
+
"invalidToken": "Neveljaven ali potekel žeton",
|
|
131
|
+
"email": "E-pošta",
|
|
132
|
+
"password": "Geslo",
|
|
133
|
+
"passwordPlaceholder": "Vnesite svoje geslo",
|
|
134
|
+
"confirmPassword": "Potrdite geslo",
|
|
135
|
+
"confirmPasswordPlaceholder": "Potrdite svoje geslo",
|
|
136
|
+
"passwordRequirements": "Geslo mora vsebovati vsaj 8 znakov.",
|
|
137
|
+
"submit": "Nastavi geslo",
|
|
138
|
+
"setPasswordFailed": "Nastavitev gesla ni uspela",
|
|
139
|
+
"hasPassword": "Že imate geslo?",
|
|
140
|
+
"loginLink": "Prijava"
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
"layout": {
|
|
145
|
+
"header": {
|
|
146
|
+
"logo": "Tiny",
|
|
147
|
+
"openMenu": "Odpri meni",
|
|
148
|
+
"closeMenu": "Zapri meni",
|
|
149
|
+
"nav": {
|
|
150
|
+
"browse": "Brskaj",
|
|
151
|
+
"sell": "Prodaj",
|
|
152
|
+
"watchlist": "Seznam spremljanja",
|
|
153
|
+
"orders": "Naročila",
|
|
154
|
+
"cart": "Košarica"
|
|
155
|
+
},
|
|
156
|
+
"profile": "Profil",
|
|
157
|
+
"logout": "Odjava"
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"browse": {
|
|
161
|
+
"head": {
|
|
162
|
+
"title": "Brskaj",
|
|
163
|
+
"description": "Iskanje blaga v prodaji"
|
|
164
|
+
},
|
|
165
|
+
"title": "Brskaj",
|
|
166
|
+
"search": "Iskanje",
|
|
167
|
+
"searchPlaceholder": "Išči oglase",
|
|
168
|
+
"allCategories": "Vse kategorije",
|
|
169
|
+
"empty": "Noben oglas ne ustreza iskanju."
|
|
170
|
+
},
|
|
171
|
+
"listing": {
|
|
172
|
+
"notFound": "Oglas ni bil najden.",
|
|
173
|
+
"soldOut": "Razprodano",
|
|
174
|
+
"inactive": "Neaktivno",
|
|
175
|
+
"seller": "Prodajalec",
|
|
176
|
+
"category": "Kategorija",
|
|
177
|
+
"shipping": "Dostava",
|
|
178
|
+
"shippingDays": "{{count}} dni",
|
|
179
|
+
"quantity": "Količina",
|
|
180
|
+
"inStock": "{{count}} na voljo",
|
|
181
|
+
"rating": "Ocena prodajalca {{rating}}",
|
|
182
|
+
"noRating": "Prodajalec še nima ocen",
|
|
183
|
+
"addToCart": "Dodaj v košarico",
|
|
184
|
+
"addedToCart": "Dodano v košarico",
|
|
185
|
+
"addToCartError": "Ni bilo mogoče dodati v košarico",
|
|
186
|
+
"watchError": "Seznama spremljanja ni bilo mogoče posodobiti",
|
|
187
|
+
"watch": "Spremljaj",
|
|
188
|
+
"unwatch": "Nehaj spremljati",
|
|
189
|
+
"ownListing": "To je vaš oglas",
|
|
190
|
+
"images": "Slike",
|
|
191
|
+
"description": "Opis",
|
|
192
|
+
"price": "Cena",
|
|
193
|
+
"reviews": "Ocene",
|
|
194
|
+
"noReviews": "Ocene še ni."
|
|
195
|
+
},
|
|
196
|
+
"sell": {
|
|
197
|
+
"head": {
|
|
198
|
+
"title": "Prodaj",
|
|
199
|
+
"description": "Vaši oglasi"
|
|
200
|
+
},
|
|
201
|
+
"title": "Moji oglasi",
|
|
202
|
+
"create": "Nov oglas",
|
|
203
|
+
"empty": "Nimate še oglasov.",
|
|
204
|
+
"soldOut": "Razprodano",
|
|
205
|
+
"inactive": "Neaktivno",
|
|
206
|
+
"edit": "Uredi",
|
|
207
|
+
"deactivate": "Deaktiviraj",
|
|
208
|
+
"deactivateSuccess": "Oglas deaktiviran",
|
|
209
|
+
"deactivateError": "Oglasa ni bilo mogoče deaktivirati"
|
|
210
|
+
},
|
|
211
|
+
"listingForm": {
|
|
212
|
+
"createTitle": "Nov oglas",
|
|
213
|
+
"editTitle": "Uredi oglas",
|
|
214
|
+
"title": "Naslov",
|
|
215
|
+
"titlePlaceholder": "Kaj prodajate?",
|
|
216
|
+
"description": "Opis",
|
|
217
|
+
"descriptionPlaceholder": "Opišite izdelek",
|
|
218
|
+
"category": "Kategorija",
|
|
219
|
+
"price": "Cena (USD)",
|
|
220
|
+
"quantity": "Količina",
|
|
221
|
+
"shipping": "Dostava (USD)",
|
|
222
|
+
"shippingDays": "Dni dostave",
|
|
223
|
+
"images": "Fotografije",
|
|
224
|
+
"imageEmptyText": "Še ni fotografij",
|
|
225
|
+
"imageUploadText": "Naloži",
|
|
226
|
+
"imageBrowseText": "Brskaj",
|
|
227
|
+
"removeImage": "Odstrani fotografijo",
|
|
228
|
+
"submitCreate": "Objavi",
|
|
229
|
+
"submitEdit": "Shrani oglas",
|
|
230
|
+
"cancel": "Prekliči",
|
|
231
|
+
"createSuccess": "Oglas ustvarjen",
|
|
232
|
+
"createError": "Oglasa ni bilo mogoče ustvariti",
|
|
233
|
+
"updateSuccess": "Oglas posodobljen",
|
|
234
|
+
"updateError": "Oglasa ni bilo mogoče posodobiti"
|
|
235
|
+
},
|
|
236
|
+
"cart": {
|
|
237
|
+
"head": {
|
|
238
|
+
"title": "Košarica",
|
|
239
|
+
"description": "Izdelki, ki jih kupujete"
|
|
240
|
+
},
|
|
241
|
+
"title": "Košarica",
|
|
242
|
+
"empty": "Košarica je prazna.",
|
|
243
|
+
"checkout": "Na blagajno",
|
|
244
|
+
"remove": "Odstrani",
|
|
245
|
+
"quantity": "Količina",
|
|
246
|
+
"updateError": "Košarice ni bilo mogoče posodobiti",
|
|
247
|
+
"removeError": "Izdelka ni bilo mogoče odstraniti",
|
|
248
|
+
"subtotal": "Vmesna vsota",
|
|
249
|
+
"shipping": "Dostava"
|
|
250
|
+
},
|
|
251
|
+
"checkout": {
|
|
252
|
+
"head": {
|
|
253
|
+
"title": "Blagajna",
|
|
254
|
+
"description": "Plačilo košarice"
|
|
255
|
+
},
|
|
256
|
+
"title": "Blagajna",
|
|
257
|
+
"shipping": "Naslov za dostavo",
|
|
258
|
+
"name": "Polno ime",
|
|
259
|
+
"line1": "Naslov 1",
|
|
260
|
+
"line2": "Naslov 2",
|
|
261
|
+
"city": "Mesto",
|
|
262
|
+
"region": "Regija",
|
|
263
|
+
"postal": "Poštna številka",
|
|
264
|
+
"country": "Država",
|
|
265
|
+
"card": "Kartica (ni bremenjena)",
|
|
266
|
+
"cardNumber": "Številka kartice",
|
|
267
|
+
"expiry": "Veljavnost",
|
|
268
|
+
"cvc": "CVC",
|
|
269
|
+
"submit": "Oddaj naročilo",
|
|
270
|
+
"success": "Naročilo oddano",
|
|
271
|
+
"error": "Blagajna ni uspela",
|
|
272
|
+
"empty": "Košarica je prazna."
|
|
273
|
+
},
|
|
274
|
+
"orders": {
|
|
275
|
+
"head": {
|
|
276
|
+
"title": "Naročila",
|
|
277
|
+
"description": "Nakupi in prodaje"
|
|
278
|
+
},
|
|
279
|
+
"title": "Naročila",
|
|
280
|
+
"purchases": "Nakupi",
|
|
281
|
+
"sales": "Prodaje",
|
|
282
|
+
"emptyPurchases": "Nimate še nakupov.",
|
|
283
|
+
"emptySales": "Nimate še prodaj.",
|
|
284
|
+
"view": "Poglej",
|
|
285
|
+
"status": {
|
|
286
|
+
"paid": "Plačano",
|
|
287
|
+
"shipped": "Poslano",
|
|
288
|
+
"completed": "Zaključeno"
|
|
289
|
+
},
|
|
290
|
+
"total": "Skupaj",
|
|
291
|
+
"ship": "Označi kot poslano",
|
|
292
|
+
"complete": "Označi kot zaključeno",
|
|
293
|
+
"shipSuccess": "Naročilo označeno kot poslano",
|
|
294
|
+
"shipError": "Naročila ni bilo mogoče poslati",
|
|
295
|
+
"completeSuccess": "Naročilo zaključeno",
|
|
296
|
+
"completeError": "Naročila ni bilo mogoče zaključiti",
|
|
297
|
+
"notFound": "Naročilo ni bilo najdeno.",
|
|
298
|
+
"review": "Napiši oceno",
|
|
299
|
+
"reviewRating": "Ocena",
|
|
300
|
+
"reviewBody": "Mnenje",
|
|
301
|
+
"reviewSubmit": "Oddaj oceno",
|
|
302
|
+
"reviewSuccess": "Ocena shranjena",
|
|
303
|
+
"reviewError": "Ocene ni bilo mogoče shraniti",
|
|
304
|
+
"reviewed": "Ocenjeno"
|
|
305
|
+
},
|
|
306
|
+
"watchlist": {
|
|
307
|
+
"head": {
|
|
308
|
+
"title": "Seznam spremljanja",
|
|
309
|
+
"description": "Oglasi, ki jih spremljate"
|
|
310
|
+
},
|
|
311
|
+
"title": "Seznam spremljanja",
|
|
312
|
+
"empty": "Ne spremljate nobenega oglasa.",
|
|
313
|
+
"remove": "Odstrani",
|
|
314
|
+
"removeError": "Spremljanja ni bilo mogoče odstraniti"
|
|
315
|
+
},
|
|
316
|
+
"profile": {
|
|
317
|
+
"head": {
|
|
318
|
+
"title": "Profil",
|
|
319
|
+
"description": "Vaš profil"
|
|
320
|
+
},
|
|
321
|
+
"form": {
|
|
322
|
+
"title": "Profil",
|
|
323
|
+
"description": "Posodobite podatke profila",
|
|
324
|
+
"email": "E-pošta",
|
|
325
|
+
"emailPlaceholder": "Vnesite svoj e-poštni naslov",
|
|
326
|
+
"name": "Ime",
|
|
327
|
+
"namePlaceholder": "Vnesite svoje ime",
|
|
328
|
+
"submit": "Shrani",
|
|
329
|
+
"submitLoading": "Shranjevanje...",
|
|
330
|
+
"notifications": {
|
|
331
|
+
"success": "Profil posodobljen",
|
|
332
|
+
"error": "Posodobitev profila ni uspela"
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { RestClient } from "@povio/openapi-codegen-cli";
|
|
2
|
+
|
|
3
|
+
import { AuthorizationHeaderInterceptor } from "@/clients/rest/interceptors/authorization-header.interceptor";
|
|
4
|
+
import { RefreshTokenInterceptor } from "@/clients/rest/interceptors/refresh-token.interceptor";
|
|
5
|
+
import { ResponseInterceptor } from "@/clients/rest/interceptors/response.interceptor";
|
|
6
|
+
import { AppConfig } from "@/config/app.config";
|
|
7
|
+
import { AppErrorHandler } from "@/clients/rest/app-error-handler";
|
|
8
|
+
|
|
9
|
+
export const AppRestClient = new RestClient({
|
|
10
|
+
config: {
|
|
11
|
+
baseURL: AppConfig.api.url,
|
|
12
|
+
},
|
|
13
|
+
errorHandler: AppErrorHandler,
|
|
14
|
+
interceptors: [AuthorizationHeaderInterceptor, RefreshTokenInterceptor, ResponseInterceptor],
|
|
15
|
+
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { ACCESS_TOKEN_KEY, REFRESH_TOKEN_KEY } from "@/config/jwt.config";
|
|
2
|
+
|
|
3
|
+
type TokenListener = () => void;
|
|
4
|
+
|
|
5
|
+
const listeners = new Set<TokenListener>();
|
|
6
|
+
let storageListenerCount = 0;
|
|
7
|
+
|
|
8
|
+
const isBrowser = () => typeof window !== "undefined";
|
|
9
|
+
|
|
10
|
+
const readToken = (key: string) => {
|
|
11
|
+
if (!isBrowser()) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
return window.localStorage.getItem(key);
|
|
17
|
+
} catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const writeToken = (key: string, token: string | null) => {
|
|
23
|
+
if (!isBrowser()) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
if (token) {
|
|
29
|
+
window.localStorage.setItem(key, token);
|
|
30
|
+
} else {
|
|
31
|
+
window.localStorage.removeItem(key);
|
|
32
|
+
}
|
|
33
|
+
} catch {
|
|
34
|
+
// Keep in-memory auth subscribers in sync even if storage is unavailable.
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const emitChange = () => {
|
|
39
|
+
for (const listener of listeners) {
|
|
40
|
+
listener();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const onStorageChange = (event: StorageEvent) => {
|
|
45
|
+
if (event.storageArea !== window.localStorage) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (event.key === ACCESS_TOKEN_KEY || event.key === REFRESH_TOKEN_KEY || event.key === null) {
|
|
50
|
+
emitChange();
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const authTokenStore = {
|
|
55
|
+
getAccessToken: () => readToken(ACCESS_TOKEN_KEY),
|
|
56
|
+
getRefreshToken: () => readToken(REFRESH_TOKEN_KEY),
|
|
57
|
+
getServerSnapshot: () => null,
|
|
58
|
+
subscribe: (listener: TokenListener) => {
|
|
59
|
+
listeners.add(listener);
|
|
60
|
+
|
|
61
|
+
if (isBrowser()) {
|
|
62
|
+
if (storageListenerCount === 0) {
|
|
63
|
+
window.addEventListener("storage", onStorageChange);
|
|
64
|
+
}
|
|
65
|
+
storageListenerCount += 1;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return () => {
|
|
69
|
+
listeners.delete(listener);
|
|
70
|
+
|
|
71
|
+
if (isBrowser()) {
|
|
72
|
+
storageListenerCount -= 1;
|
|
73
|
+
if (storageListenerCount === 0) {
|
|
74
|
+
window.removeEventListener("storage", onStorageChange);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
setAccessToken: (token: string | null) => {
|
|
80
|
+
writeToken(ACCESS_TOKEN_KEY, token);
|
|
81
|
+
emitChange();
|
|
82
|
+
},
|
|
83
|
+
setRefreshToken: (token: string | null) => {
|
|
84
|
+
writeToken(REFRESH_TOKEN_KEY, token);
|
|
85
|
+
emitChange();
|
|
86
|
+
},
|
|
87
|
+
setTokens: (accessToken: string | null, refreshToken?: string | null) => {
|
|
88
|
+
writeToken(ACCESS_TOKEN_KEY, accessToken);
|
|
89
|
+
|
|
90
|
+
if (refreshToken !== undefined) {
|
|
91
|
+
writeToken(REFRESH_TOKEN_KEY, refreshToken);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
emitChange();
|
|
95
|
+
},
|
|
96
|
+
clear: () => {
|
|
97
|
+
writeToken(ACCESS_TOKEN_KEY, null);
|
|
98
|
+
writeToken(REFRESH_TOKEN_KEY, null);
|
|
99
|
+
emitChange();
|
|
100
|
+
},
|
|
101
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type ErrorEntry, ErrorHandler } from "@povio/openapi-codegen-cli";
|
|
2
|
+
|
|
3
|
+
export enum AuthErrorCodes {
|
|
4
|
+
InvalidCredentials = "invalid-credentials",
|
|
5
|
+
LocalAuthnIdentityExists = "identity-already-exists",
|
|
6
|
+
IdentityNotFound = "identity-not-found",
|
|
7
|
+
NotConfirmed = "identity-not-confirmed",
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const authErrors: ErrorEntry<AuthErrorCodes>[] = [
|
|
11
|
+
{
|
|
12
|
+
code: AuthErrorCodes.InvalidCredentials,
|
|
13
|
+
getMessage: (t) => t("auth.shared.errors.invalidCredentials"),
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
code: AuthErrorCodes.LocalAuthnIdentityExists,
|
|
17
|
+
getMessage: (t) => t("auth.shared.errors.userAlreadyExists"),
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
code: AuthErrorCodes.IdentityNotFound,
|
|
21
|
+
getMessage: (t) => t("auth.shared.errors.identityNotFound"),
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
code: AuthErrorCodes.NotConfirmed,
|
|
25
|
+
getMessage: (t) => t("auth.shared.errors.notConfirmed"),
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const entries = [...authErrors];
|
|
30
|
+
|
|
31
|
+
export const AppErrorHandler = new ErrorHandler({ entries });
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { RestInterceptor } from "@povio/openapi-codegen-cli";
|
|
2
|
+
|
|
3
|
+
import { authTokenStore } from "@/clients/auth-token-store";
|
|
4
|
+
|
|
5
|
+
export const AuthorizationHeaderInterceptor = new RestInterceptor((client) => {
|
|
6
|
+
return client.interceptors.request.use(async (config) => {
|
|
7
|
+
const accessToken = authTokenStore.getAccessToken();
|
|
8
|
+
if (accessToken != null) {
|
|
9
|
+
// oxlint-disable-next-line no-param-reassign
|
|
10
|
+
config.headers.Authorization = `Bearer ${accessToken}`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return config;
|
|
14
|
+
});
|
|
15
|
+
});
|
package/templates/marketplace/apps/fe/src/clients/rest/interceptors/refresh-token.interceptor.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { RestInterceptor } from "@povio/openapi-codegen-cli";
|
|
2
|
+
|
|
3
|
+
import { AuthErrorCodes } from "@/clients/rest/app-error-handler";
|
|
4
|
+
import { UserAuthApi } from "@/openapi/userAuth/userAuth.api";
|
|
5
|
+
import { authTokenStore } from "@/clients/auth-token-store";
|
|
6
|
+
|
|
7
|
+
export const RefreshTokenInterceptor = new RestInterceptor((client) => {
|
|
8
|
+
return client.interceptors.response.use(
|
|
9
|
+
(response) => response,
|
|
10
|
+
// oxlint-disable-next-line promise/prefer-await-to-callbacks
|
|
11
|
+
async (error) => {
|
|
12
|
+
const originalRequest = error.config;
|
|
13
|
+
|
|
14
|
+
if (error.response?.data?.code === AuthErrorCodes.InvalidCredentials) {
|
|
15
|
+
return Promise.reject(error);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (error.response?.status === 401 && !originalRequest._retry) {
|
|
19
|
+
originalRequest._retry = true;
|
|
20
|
+
try {
|
|
21
|
+
const refreshToken = authTokenStore.getRefreshToken();
|
|
22
|
+
const { accessToken, refreshToken: newRefreshToken } = await UserAuthApi.accessToken({
|
|
23
|
+
refreshToken: refreshToken || "",
|
|
24
|
+
});
|
|
25
|
+
authTokenStore.setTokens(accessToken, newRefreshToken || null);
|
|
26
|
+
|
|
27
|
+
originalRequest.headers.Authorization = `Bearer ${accessToken}`;
|
|
28
|
+
|
|
29
|
+
return client(originalRequest);
|
|
30
|
+
} catch {
|
|
31
|
+
authTokenStore.clear();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return Promise.reject(error);
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RestInterceptor } from "@povio/openapi-codegen-cli";
|
|
2
|
+
import type { AxiosError, AxiosResponse } from "axios";
|
|
3
|
+
|
|
4
|
+
export const ResponseInterceptor = new RestInterceptor((client) => {
|
|
5
|
+
return client.interceptors.response.use(
|
|
6
|
+
async (response: AxiosResponse) => {
|
|
7
|
+
return {
|
|
8
|
+
...response,
|
|
9
|
+
data: response.data === "" ? undefined : response.data,
|
|
10
|
+
};
|
|
11
|
+
},
|
|
12
|
+
// oxlint-disable-next-line promise/prefer-await-to-callbacks
|
|
13
|
+
async (error: AxiosError) => {
|
|
14
|
+
throw error;
|
|
15
|
+
},
|
|
16
|
+
);
|
|
17
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useTranslation } from "react-i18next";
|
|
2
|
+
|
|
3
|
+
import { NotFound } from "@/components/shared/error/NotFound";
|
|
4
|
+
import { AppHead } from "@/components/shared/head/AppHead";
|
|
5
|
+
|
|
6
|
+
export const NotFoundPage = () => {
|
|
7
|
+
const { t } = useTranslation();
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<>
|
|
11
|
+
<AppHead
|
|
12
|
+
title={t(($) => $.shared.notFound.head.title)}
|
|
13
|
+
description={t(($) => $.shared.notFound.head.description)}
|
|
14
|
+
/>
|
|
15
|
+
<NotFound />
|
|
16
|
+
</>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Typography } from "@povio/ui";
|
|
2
|
+
import { useTranslation } from "react-i18next";
|
|
3
|
+
|
|
4
|
+
import { BrandLogo } from "@/components/shared/branding/BrandLogo";
|
|
5
|
+
|
|
6
|
+
export function AuthBrandPanel() {
|
|
7
|
+
const { t } = useTranslation();
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<section className="relative hidden flex-1 overflow-hidden bg-elevation-fill-default-2 lg:flex lg:flex-col lg:justify-between">
|
|
11
|
+
<div className="relative z-raised flex flex-col gap-1 px-16 pt-20 xl:px-24 xl:pt-24">
|
|
12
|
+
<Typography
|
|
13
|
+
as="p"
|
|
14
|
+
className="text-text-default-2"
|
|
15
|
+
size="title-3"
|
|
16
|
+
>
|
|
17
|
+
{t(($) => $.auth.wrapper.title)}
|
|
18
|
+
</Typography>
|
|
19
|
+
<Typography
|
|
20
|
+
as="h1"
|
|
21
|
+
className="text-text-default-2"
|
|
22
|
+
size="title-1"
|
|
23
|
+
variant="prominent-1"
|
|
24
|
+
>
|
|
25
|
+
{t(($) => $.auth.wrapper.description)}
|
|
26
|
+
</Typography>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<BrandLogo className="absolute -right-12 top-10 text-[10rem] leading-none text-[#e1e9ee]" />
|
|
30
|
+
|
|
31
|
+
<svg
|
|
32
|
+
aria-hidden="true"
|
|
33
|
+
className="absolute bottom-0 left-0 h-auto w-full opacity-20"
|
|
34
|
+
viewBox="0 0 760 390"
|
|
35
|
+
>
|
|
36
|
+
<path
|
|
37
|
+
d="M0 245 80 202l62 22 98-85 92 77 68-45 76 53 84-113 74 95 126-50v234H0Z"
|
|
38
|
+
fill="#006ab6"
|
|
39
|
+
/>
|
|
40
|
+
<path
|
|
41
|
+
d="m52 390 132-120 78 61 106-130 91 108 69-59 128 140Z"
|
|
42
|
+
fill="#006ab6"
|
|
43
|
+
opacity=".4"
|
|
44
|
+
/>
|
|
45
|
+
</svg>
|
|
46
|
+
|
|
47
|
+
<div className="relative z-raised flex flex-col items-center gap-3 pb-8">
|
|
48
|
+
<BrandLogo className="text-interactive-contained-primary-idle" />
|
|
49
|
+
<Typography
|
|
50
|
+
as="span"
|
|
51
|
+
className="text-text-default-2"
|
|
52
|
+
size="body-4"
|
|
53
|
+
variant="prominent-1"
|
|
54
|
+
>
|
|
55
|
+
{t(($) => $.auth.wrapper.watermark, { year: new Date().getFullYear() })}
|
|
56
|
+
</Typography>
|
|
57
|
+
</div>
|
|
58
|
+
</section>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { PropsWithChildren } from "react";
|
|
2
|
+
|
|
3
|
+
import { BrandLogo } from "@/components/shared/branding/BrandLogo";
|
|
4
|
+
|
|
5
|
+
import { AuthBrandPanel } from "./AuthBrandPanel";
|
|
6
|
+
|
|
7
|
+
export function AuthLayout({ children }: PropsWithChildren) {
|
|
8
|
+
return (
|
|
9
|
+
<div className="flex min-h-dvh w-full overflow-hidden bg-elevation-fill-default-2">
|
|
10
|
+
<AuthBrandPanel />
|
|
11
|
+
|
|
12
|
+
<section className="m-4 flex w-full flex-1 flex-col rounded-sm bg-elevation-fill-default-1 lg:m-0 lg:rounded-none">
|
|
13
|
+
<div className="flex flex-1 items-center justify-center px-4 py-10 sm:px-8">
|
|
14
|
+
<div className="w-full max-w-[440px]">{children}</div>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div className="flex justify-center pb-6 lg:hidden">
|
|
18
|
+
<BrandLogo className="text-interactive-contained-primary-idle" />
|
|
19
|
+
</div>
|
|
20
|
+
</section>
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
23
|
+
}
|