@promakeai/cli 0.3.2 → 0.3.4
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/dist/index.js +415 -209
- package/dist/registry/about-page.json +3 -3
- package/dist/registry/about-section.json +4 -4
- package/dist/registry/animations.json +2 -2
- package/dist/registry/announcement-bar.json +4 -4
- package/dist/registry/api.json +1 -1
- package/dist/registry/auth-core.json +3 -3
- package/dist/registry/auth.json +70 -0
- package/dist/registry/bento-grid-section.json +4 -4
- package/dist/registry/blog-core.json +5 -5
- package/dist/registry/blog-list-page.json +3 -3
- package/dist/registry/blog-section.json +4 -4
- package/dist/registry/cards-carousel-section.json +4 -4
- package/dist/registry/cart-drawer.json +3 -3
- package/dist/registry/cart-page.json +3 -3
- package/dist/registry/case-study-page.json +3 -3
- package/dist/registry/category-section.json +3 -3
- package/dist/registry/checkout-page.json +3 -3
- package/dist/registry/coming-soon-page-minimal.json +4 -4
- package/dist/registry/coming-soon-page.json +4 -4
- package/dist/registry/contact-info-grid.json +4 -4
- package/dist/registry/contact-page-centered.json +4 -4
- package/dist/registry/contact-page-split.json +4 -4
- package/dist/registry/contact-page.json +3 -3
- package/dist/registry/content-section.json +4 -4
- package/dist/registry/cookie-consent.json +4 -4
- package/dist/registry/cookies-page.json +3 -3
- package/dist/registry/cta-section.json +3 -3
- package/dist/registry/docs/reset-password-page.md +36 -0
- package/dist/registry/ecommerce-core.json +10 -10
- package/dist/registry/empty-page.json +3 -3
- package/dist/registry/faq-categorized.json +4 -4
- package/dist/registry/faq-simple.json +4 -4
- package/dist/registry/favorites-blog-block.json +1 -1
- package/dist/registry/favorites-blog-page.json +4 -4
- package/dist/registry/favorites-ecommerce-block.json +1 -1
- package/dist/registry/favorites-ecommerce-page.json +4 -4
- package/dist/registry/feature-section.json +3 -3
- package/dist/registry/featured-products.json +3 -3
- package/dist/registry/footer-detailed.json +4 -4
- package/dist/registry/footer-minimal.json +3 -3
- package/dist/registry/footer.json +3 -3
- package/dist/registry/forgot-password-page-split.json +4 -4
- package/dist/registry/forgot-password-page.json +4 -4
- package/dist/registry/google-adsense.json +4 -4
- package/dist/registry/google-map.json +2 -2
- package/dist/registry/header-centered-pill.json +4 -4
- package/dist/registry/header-ecommerce.json +3 -3
- package/dist/registry/header-mega.json +4 -4
- package/dist/registry/header-minimal.json +4 -4
- package/dist/registry/header-simple.json +3 -3
- package/dist/registry/hero-carousel.json +3 -3
- package/dist/registry/hero-cta.json +4 -4
- package/dist/registry/hero-gradient.json +4 -4
- package/dist/registry/hero-grid.json +4 -4
- package/dist/registry/hero-profile.json +3 -3
- package/dist/registry/hero.json +3 -3
- package/dist/registry/landing-page-app.json +3 -3
- package/dist/registry/landing-page-saas.json +3 -3
- package/dist/registry/login-page-split.json +4 -4
- package/dist/registry/login-page.json +4 -4
- package/dist/registry/logo-cloud.json +4 -4
- package/dist/registry/masonry-grid.json +3 -3
- package/dist/registry/my-orders-page.json +4 -4
- package/dist/registry/newsletter-section.json +4 -4
- package/dist/registry/order-card-compact.json +1 -1
- package/dist/registry/order-confirmation-page.json +4 -4
- package/dist/registry/order-detail-block.json +1 -1
- package/dist/registry/orders-list-block.json +1 -1
- package/dist/registry/payment-success-block.json +1 -1
- package/dist/registry/portfolio-page.json +4 -4
- package/dist/registry/post-card.json +3 -3
- package/dist/registry/post-detail-block.json +1 -1
- package/dist/registry/post-detail-page.json +4 -4
- package/dist/registry/pricing-card.json +3 -3
- package/dist/registry/pricing-page.json +4 -4
- package/dist/registry/pricing-section.json +4 -4
- package/dist/registry/privacy-page.json +3 -3
- package/dist/registry/product-card-detailed.json +4 -4
- package/dist/registry/product-card-hover.json +4 -4
- package/dist/registry/product-card.json +3 -3
- package/dist/registry/product-detail-block.json +1 -1
- package/dist/registry/product-detail-page.json +4 -4
- package/dist/registry/product-detail-section.json +4 -4
- package/dist/registry/product-quick-view.json +4 -4
- package/dist/registry/products-page.json +3 -3
- package/dist/registry/reading-progress.json +4 -4
- package/dist/registry/register-page-split.json +4 -4
- package/dist/registry/register-page.json +4 -4
- package/dist/registry/related-posts-block.json +1 -1
- package/dist/registry/related-products-block.json +1 -1
- package/dist/registry/reset-password-page-split.json +4 -4
- package/dist/registry/reset-password-page.json +39 -0
- package/dist/registry/service-card.json +1 -1
- package/dist/registry/share-buttons.json +4 -4
- package/dist/registry/skill-card.json +1 -1
- package/dist/registry/team-page.json +4 -4
- package/dist/registry/terms-page.json +3 -3
- package/dist/registry/testimonials-carousel.json +4 -4
- package/dist/registry/testimonials-grid.json +4 -4
- package/dist/registry/timeline-section.json +4 -4
- package/dist/registry/video-hero.json +4 -4
- package/dist/registry/youtube-embed.json +4 -4
- package/package.json +2 -2
- package/template/.env +6 -6
- package/template/public/_redirects +1 -1
- package/template/public/robots.txt +14 -14
- package/template/src/components/GoogleAnalytics.tsx +34 -34
- package/template/src/components/LanguageSwitcher.tsx +53 -53
- package/template/src/components/ScriptInjector.tsx +62 -62
- package/template/src/lib/env.ts +19 -19
- package/template/src/router.tsx +14 -14
- package/template/src/vite-env.d.ts +1 -1
|
@@ -17,25 +17,25 @@
|
|
|
17
17
|
"path": "login-page-split/index.ts",
|
|
18
18
|
"type": "registry:index",
|
|
19
19
|
"target": "$modules$/login-page-split/index.ts",
|
|
20
|
-
"content": "export * from './login-page-split';\nexport { default } from './login-page-split';\n"
|
|
20
|
+
"content": "export * from './login-page-split';\r\nexport { default } from './login-page-split';\r\n"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
"path": "login-page-split/login-page-split.tsx",
|
|
24
24
|
"type": "registry:page",
|
|
25
25
|
"target": "$modules$/login-page-split/login-page-split.tsx",
|
|
26
|
-
"content": "import { useState } from \"react\";\nimport { Link, useNavigate, useLocation } from \"react-router\";\nimport { toast } from \"sonner\";\nimport { Logo } from \"@/components/Logo\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { useTranslation } from \"react-i18next\";\nimport { useAuth } from \"@/modules/auth-core\";\nimport { getErrorMessage } from \"@/modules/api\";\n\ninterface LoginPageSplitProps {\n image?: string;\n}\n\nexport function LoginPageSplit({\n image = \"/images/placeholder.png\",\n}: LoginPageSplitProps) {\n const { t } = useTranslation(\"login-page-split\");\n const navigate = useNavigate();\n const location = useLocation();\n const { login } = useAuth();\n\n const [username, setUsername] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // Get redirect URL from location state or default to home\n const from = (location.state as { from?: string })?.from || \"/\";\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n setIsLoading(true);\n\n try {\n await login(username, password);\n toast.success(t(\"loginSuccess\", \"Login successful!\"));\n navigate(from, { replace: true });\n } catch (err) {\n const errorMessage = getErrorMessage(\n err,\n t(\"loginError\", \"Login failed. Please check your credentials.\")\n );\n setError(errorMessage);\n } finally {\n setIsLoading(false);\n }\n };\n\n return (\n <section className=\"w-full md:grid md:min-h-screen md:grid-cols-2\">\n <div className=\"flex items-center justify-center px-4 py-12\">\n <div className=\"mx-auto grid w-full max-w-sm gap-6\">\n <Logo />\n <hr />\n <div>\n <h1 className=\"text-xl font-bold tracking-tight\">\n {t(\"title\", \"Login\")}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"subtitle\", \"Enter your details below to login\")}\n </p>\n </div>\n\n {error && (\n <div className=\"p-3 text-sm text-red-600 bg-red-50 dark:bg-red-950 dark:text-red-400 rounded-md\">\n {error}\n </div>\n )}\n\n <form onSubmit={handleSubmit} className=\"grid gap-4\">\n <div className=\"grid gap-2\">\n <Label htmlFor=\"username-split\">{t(\"username\", \"Username\")}</Label>\n <Input\n required\n id=\"username-split\"\n type=\"text\"\n autoComplete=\"username\"\n placeholder={t(\"usernamePlaceholder\", \"Enter your username\")}\n value={username}\n onChange={(e) => setUsername(e.target.value)}\n disabled={isLoading}\n />\n </div>\n <div className=\"grid gap-2\">\n <Label htmlFor=\"password-split\">{t(\"password\", \"Password\")}</Label>\n <Input\n required\n id=\"password-split\"\n type=\"password\"\n placeholder=\"••••••••••\"\n autoComplete=\"current-password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n disabled={isLoading}\n />\n </div>\n\n <Button type=\"submit\" className=\"w-full\" disabled={isLoading}>\n {isLoading ? (\n <>\n <div className=\"w-4 h-4 border-2 border-primary-foreground border-t-transparent rounded-full animate-spin mr-2\" />\n {t(\"loggingIn\", \"Logging in...\")}\n </>\n ) : (\n t(\"login\", \"Login\")\n )}\n </Button>\n </form>\n\n <div className=\"flex flex-col gap-4 text-sm\">\n <p>\n {t(\"noAccount\", \"Don't have an account?\")}{\" \"}\n <Link to=\"/register\" className=\"underline\">\n {t(\"signUp\", \"Sign up\")}\n </Link>\n </p>\n <Link to=\"/forgot-password\" className=\"underline\">\n {t(\"forgotPassword\", \"Forgot your password?\")}\n </Link>\n </div>\n <hr />\n <p className=\"text-sm text-muted-foreground\">\n © {new Date().getFullYear()} {t(\"copyright\", \"All rights reserved.\")}\n </p>\n </div>\n </div>\n <div className=\"hidden p-4 md:block\">\n <img\n loading=\"lazy\"\n decoding=\"async\"\n width=\"1920\"\n height=\"1080\"\n alt={t(\"imageAlt\", \"Login background\")}\n src={image}\n className=\"size-full rounded-lg border bg-muted object-cover object-center\"\n />\n </div>\n </section>\n );\n}\n\nexport default LoginPageSplit;\n"
|
|
26
|
+
"content": "import { useState } from \"react\";\r\nimport { Link, useNavigate, useLocation } from \"react-router\";\r\nimport { toast } from \"sonner\";\r\nimport { Logo } from \"@/components/Logo\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Label } from \"@/components/ui/label\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { useAuth } from \"@/modules/auth-core\";\r\nimport { getErrorMessage } from \"@/modules/api\";\r\n\r\ninterface LoginPageSplitProps {\r\n image?: string;\r\n}\r\n\r\nexport function LoginPageSplit({\r\n image = \"/images/placeholder.png\",\r\n}: LoginPageSplitProps) {\r\n const { t } = useTranslation(\"login-page-split\");\r\n const navigate = useNavigate();\r\n const location = useLocation();\r\n const { login } = useAuth();\r\n\r\n const [username, setUsername] = useState(\"\");\r\n const [password, setPassword] = useState(\"\");\r\n const [isLoading, setIsLoading] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n // Get redirect URL from location state or default to home\r\n const from = (location.state as { from?: string })?.from || \"/\";\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setError(null);\r\n setIsLoading(true);\r\n\r\n try {\r\n await login(username, password);\r\n toast.success(t(\"loginSuccess\", \"Login successful!\"));\r\n navigate(from, { replace: true });\r\n } catch (err) {\r\n const errorMessage = getErrorMessage(\r\n err,\r\n t(\"loginError\", \"Login failed. Please check your credentials.\")\r\n );\r\n setError(errorMessage);\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n };\r\n\r\n return (\r\n <section className=\"w-full md:grid md:min-h-screen md:grid-cols-2\">\r\n <div className=\"flex items-center justify-center px-4 py-12\">\r\n <div className=\"mx-auto grid w-full max-w-sm gap-6\">\r\n <Logo />\r\n <hr />\r\n <div>\r\n <h1 className=\"text-xl font-bold tracking-tight\">\r\n {t(\"title\", \"Login\")}\r\n </h1>\r\n <p className=\"text-sm text-muted-foreground\">\r\n {t(\"subtitle\", \"Enter your details below to login\")}\r\n </p>\r\n </div>\r\n\r\n {error && (\r\n <div className=\"p-3 text-sm text-red-600 bg-red-50 dark:bg-red-950 dark:text-red-400 rounded-md\">\r\n {error}\r\n </div>\r\n )}\r\n\r\n <form onSubmit={handleSubmit} className=\"grid gap-4\">\r\n <div className=\"grid gap-2\">\r\n <Label htmlFor=\"username-split\">{t(\"username\", \"Username\")}</Label>\r\n <Input\r\n required\r\n id=\"username-split\"\r\n type=\"text\"\r\n autoComplete=\"username\"\r\n placeholder={t(\"usernamePlaceholder\", \"Enter your username\")}\r\n value={username}\r\n onChange={(e) => setUsername(e.target.value)}\r\n disabled={isLoading}\r\n />\r\n </div>\r\n <div className=\"grid gap-2\">\r\n <Label htmlFor=\"password-split\">{t(\"password\", \"Password\")}</Label>\r\n <Input\r\n required\r\n id=\"password-split\"\r\n type=\"password\"\r\n placeholder=\"••••••••••\"\r\n autoComplete=\"current-password\"\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n disabled={isLoading}\r\n />\r\n </div>\r\n\r\n <Button type=\"submit\" className=\"w-full\" disabled={isLoading}>\r\n {isLoading ? (\r\n <>\r\n <div className=\"w-4 h-4 border-2 border-primary-foreground border-t-transparent rounded-full animate-spin mr-2\" />\r\n {t(\"loggingIn\", \"Logging in...\")}\r\n </>\r\n ) : (\r\n t(\"login\", \"Login\")\r\n )}\r\n </Button>\r\n </form>\r\n\r\n <div className=\"flex flex-col gap-4 text-sm\">\r\n <p>\r\n {t(\"noAccount\", \"Don't have an account?\")}{\" \"}\r\n <Link to=\"/register\" className=\"underline\">\r\n {t(\"signUp\", \"Sign up\")}\r\n </Link>\r\n </p>\r\n <Link to=\"/forgot-password\" className=\"underline\">\r\n {t(\"forgotPassword\", \"Forgot your password?\")}\r\n </Link>\r\n </div>\r\n <hr />\r\n <p className=\"text-sm text-muted-foreground\">\r\n © {new Date().getFullYear()} {t(\"copyright\", \"All rights reserved.\")}\r\n </p>\r\n </div>\r\n </div>\r\n <div className=\"hidden p-4 md:block\">\r\n <img\r\n loading=\"lazy\"\r\n decoding=\"async\"\r\n width=\"1920\"\r\n height=\"1080\"\r\n alt={t(\"imageAlt\", \"Login background\")}\r\n src={image}\r\n className=\"size-full rounded-lg border bg-muted object-cover object-center\"\r\n />\r\n </div>\r\n </section>\r\n );\r\n}\r\n\r\nexport default LoginPageSplit;\r\n"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
"path": "login-page-split/lang/en.json",
|
|
30
30
|
"type": "registry:lang",
|
|
31
31
|
"target": "$modules$/login-page-split/lang/en.json",
|
|
32
|
-
"content": "{\n \"title\": \"Login\",\n \"subtitle\": \"Enter your details below to login\",\n \"username\": \"Username\",\n \"usernamePlaceholder\": \"Enter your username\",\n \"email\": \"Email\",\n \"emailPlaceholder\": \"email@example.com\",\n \"password\": \"Password\",\n \"login\": \"Login\",\n \"loggingIn\": \"Logging in...\",\n \"loginSuccess\": \"Login successful!\",\n \"loginError\": \"Login failed. Please check your credentials.\",\n \"loginGoogle\": \"Login with Google\",\n \"noAccount\": \"Don't have an account?\",\n \"signUp\": \"Sign up\",\n \"forgotPassword\": \"Forgot your password?\",\n \"copyright\": \"All rights reserved.\",\n \"imageAlt\": \"Login background\"\n}\n"
|
|
32
|
+
"content": "{\r\n \"title\": \"Login\",\r\n \"subtitle\": \"Enter your details below to login\",\r\n \"username\": \"Username\",\r\n \"usernamePlaceholder\": \"Enter your username\",\r\n \"email\": \"Email\",\r\n \"emailPlaceholder\": \"email@example.com\",\r\n \"password\": \"Password\",\r\n \"login\": \"Login\",\r\n \"loggingIn\": \"Logging in...\",\r\n \"loginSuccess\": \"Login successful!\",\r\n \"loginError\": \"Login failed. Please check your credentials.\",\r\n \"loginGoogle\": \"Login with Google\",\r\n \"noAccount\": \"Don't have an account?\",\r\n \"signUp\": \"Sign up\",\r\n \"forgotPassword\": \"Forgot your password?\",\r\n \"copyright\": \"All rights reserved.\",\r\n \"imageAlt\": \"Login background\"\r\n}\r\n"
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
"path": "login-page-split/lang/tr.json",
|
|
36
36
|
"type": "registry:lang",
|
|
37
37
|
"target": "$modules$/login-page-split/lang/tr.json",
|
|
38
|
-
"content": "{\n \"title\": \"Giriş Yap\",\n \"subtitle\": \"Giriş yapmak için bilgilerinizi girin\",\n \"username\": \"Kullanıcı Adı\",\n \"usernamePlaceholder\": \"Kullanıcı adınızı girin\",\n \"email\": \"E-posta\",\n \"emailPlaceholder\": \"eposta@ornek.com\",\n \"password\": \"Şifre\",\n \"login\": \"Giriş Yap\",\n \"loggingIn\": \"Giriş yapılıyor...\",\n \"loginSuccess\": \"Giriş başarılı!\",\n \"loginError\": \"Giriş başarısız. Lütfen bilgilerinizi kontrol edin.\",\n \"loginGoogle\": \"Google ile Giriş Yap\",\n \"noAccount\": \"Hesabınız yok mu?\",\n \"signUp\": \"Kayıt Ol\",\n \"forgotPassword\": \"Şifrenizi mi unuttunuz?\",\n \"copyright\": \"Tüm hakları saklıdır.\",\n \"imageAlt\": \"Giriş arka planı\"\n}\n"
|
|
38
|
+
"content": "{\r\n \"title\": \"Giriş Yap\",\r\n \"subtitle\": \"Giriş yapmak için bilgilerinizi girin\",\r\n \"username\": \"Kullanıcı Adı\",\r\n \"usernamePlaceholder\": \"Kullanıcı adınızı girin\",\r\n \"email\": \"E-posta\",\r\n \"emailPlaceholder\": \"eposta@ornek.com\",\r\n \"password\": \"Şifre\",\r\n \"login\": \"Giriş Yap\",\r\n \"loggingIn\": \"Giriş yapılıyor...\",\r\n \"loginSuccess\": \"Giriş başarılı!\",\r\n \"loginError\": \"Giriş başarısız. Lütfen bilgilerinizi kontrol edin.\",\r\n \"loginGoogle\": \"Google ile Giriş Yap\",\r\n \"noAccount\": \"Hesabınız yok mu?\",\r\n \"signUp\": \"Kayıt Ol\",\r\n \"forgotPassword\": \"Şifrenizi mi unuttunuz?\",\r\n \"copyright\": \"Tüm hakları saklıdır.\",\r\n \"imageAlt\": \"Giriş arka planı\"\r\n}\r\n"
|
|
39
39
|
}
|
|
40
40
|
],
|
|
41
41
|
"exports": {
|
|
@@ -17,25 +17,25 @@
|
|
|
17
17
|
"path": "login-page/index.ts",
|
|
18
18
|
"type": "registry:index",
|
|
19
19
|
"target": "$modules$/login-page/index.ts",
|
|
20
|
-
"content": "export * from './login-page';\nexport { default } from './login-page';\n"
|
|
20
|
+
"content": "export * from './login-page';\r\nexport { default } from './login-page';\r\n"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
"path": "login-page/login-page.tsx",
|
|
24
24
|
"type": "registry:page",
|
|
25
25
|
"target": "$modules$/login-page/login-page.tsx",
|
|
26
|
-
"content": "import { useState } from \"react\";\nimport { Link, useNavigate, useLocation } from \"react-router\";\nimport { useTranslation } from \"react-i18next\";\nimport { toast } from \"sonner\";\nimport { usePageTitle } from \"@/hooks/use-page-title\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { Logo } from \"@/components/Logo\";\nimport { cn } from \"@/lib/utils\";\nimport { useAuth } from \"@/modules/auth-core\";\nimport { getErrorMessage } from \"@/modules/api\";\n\ninterface LoginPageProps {\n className?: string;\n}\n\nexport function LoginPage({ className }: LoginPageProps) {\n const { t } = useTranslation(\"login-page\");\n usePageTitle({ title: t(\"title\", \"Sign In\") });\n const navigate = useNavigate();\n const location = useLocation();\n const { login } = useAuth();\n\n const [username, setUsername] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const from = (location.state as { from?: string })?.from || \"/\";\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n setIsLoading(true);\n\n try {\n await login(username, password);\n toast.success(t(\"loginSuccess\", \"Login successful!\"));\n navigate(from, { replace: true });\n } catch (err) {\n const errorMessage = getErrorMessage(\n err,\n t(\"loginError\", \"Login failed. Please check your credentials.\")\n );\n setError(errorMessage);\n } finally {\n setIsLoading(false);\n }\n };\n\n return (\n <section\n className={cn(\"flex min-h-screen bg-muted/30 px-4 py-16 md:py-32\", className)}\n >\n <form\n onSubmit={handleSubmit}\n className=\"bg-muted m-auto h-fit w-full max-w-sm overflow-hidden rounded-xl border shadow-md\"\n >\n <div className=\"bg-card -m-px rounded-xl border p-8 pb-6\">\n <div className=\"text-center\">\n <Link to=\"/\" aria-label=\"go home\" className=\"mx-auto block w-fit\">\n <Logo size=\"sm\" />\n </Link>\n <h1 className=\"mb-1 mt-4 text-xl font-semibold\">\n {t(\"title\", \"Sign In\")}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"subtitle\", \"Welcome back! Sign in to continue\")}\n </p>\n </div>\n\n {error && (\n <div className=\"mt-4 p-3 text-sm text-red-600 bg-red-50 dark:bg-red-950 dark:text-red-400 rounded-md\">\n {error}\n </div>\n )}\n\n <div className=\"mt-6 space-y-6\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"username\" className=\"block text-sm\">\n {t(\"username\", \"Username\")}\n </Label>\n <Input\n type=\"text\"\n required\n name=\"username\"\n id=\"username\"\n autoComplete=\"username\"\n value={username}\n onChange={(e) => setUsername(e.target.value)}\n placeholder={t(\"usernamePlaceholder\", \"Enter your username\")}\n disabled={isLoading}\n />\n </div>\n\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between\">\n <Label htmlFor=\"password\" className=\"text-sm\">\n {t(\"password\", \"Password\")}\n </Label>\n <Button asChild variant=\"link\" size=\"sm\" className=\"h-auto p-0\">\n <Link to=\"/forgot-password\" className=\"text-xs\">\n {t(\"forgotPassword\", \"Forgot password?\")}\n </Link>\n </Button>\n </div>\n <Input\n type=\"password\"\n required\n name=\"password\"\n id=\"password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n placeholder=\"••••••••\"\n disabled={isLoading}\n />\n </div>\n\n <Button type=\"submit\" className=\"w-full\" disabled={isLoading}>\n {isLoading ? (\n <>\n <div className=\"w-4 h-4 border-2 border-primary-foreground border-t-transparent rounded-full animate-spin mr-2\" />\n {t(\"signingIn\", \"Signing in...\")}\n </>\n ) : (\n t(\"signIn\", \"Sign In\")\n )}\n </Button>\n </div>\n </div>\n\n <div className=\"p-3\">\n <p className=\"text-center text-sm text-muted-foreground\">\n {t(\"noAccount\", \"Don't have an account?\")}\n <Button asChild variant=\"link\" className=\"px-2\">\n <Link to=\"/register\">{t(\"createAccount\", \"Create account\")}</Link>\n </Button>\n </p>\n </div>\n </form>\n </section>\n );\n}\n\nexport default LoginPage;\n"
|
|
26
|
+
"content": "import { useState } from \"react\";\r\nimport { Link, useNavigate, useLocation } from \"react-router\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { toast } from \"sonner\";\r\nimport { usePageTitle } from \"@/hooks/use-page-title\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Label } from \"@/components/ui/label\";\r\nimport { Logo } from \"@/components/Logo\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { useAuth } from \"@/modules/auth-core\";\r\nimport { getErrorMessage } from \"@/modules/api\";\r\n\r\ninterface LoginPageProps {\r\n className?: string;\r\n}\r\n\r\nexport function LoginPage({ className }: LoginPageProps) {\r\n const { t } = useTranslation(\"login-page\");\r\n usePageTitle({ title: t(\"title\", \"Sign In\") });\r\n const navigate = useNavigate();\r\n const location = useLocation();\r\n const { login } = useAuth();\r\n\r\n const [username, setUsername] = useState(\"\");\r\n const [password, setPassword] = useState(\"\");\r\n const [isLoading, setIsLoading] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const from = (location.state as { from?: string })?.from || \"/\";\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setError(null);\r\n setIsLoading(true);\r\n\r\n try {\r\n await login(username, password);\r\n toast.success(t(\"loginSuccess\", \"Login successful!\"));\r\n navigate(from, { replace: true });\r\n } catch (err) {\r\n const errorMessage = getErrorMessage(\r\n err,\r\n t(\"loginError\", \"Login failed. Please check your credentials.\")\r\n );\r\n setError(errorMessage);\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n };\r\n\r\n return (\r\n <section\r\n className={cn(\"flex min-h-screen bg-muted/30 px-4 py-16 md:py-32\", className)}\r\n >\r\n <form\r\n onSubmit={handleSubmit}\r\n className=\"bg-muted m-auto h-fit w-full max-w-sm overflow-hidden rounded-xl border shadow-md\"\r\n >\r\n <div className=\"bg-card -m-px rounded-xl border p-8 pb-6\">\r\n <div className=\"text-center\">\r\n <Link to=\"/\" aria-label=\"go home\" className=\"mx-auto block w-fit\">\r\n <Logo size=\"sm\" />\r\n </Link>\r\n <h1 className=\"mb-1 mt-4 text-xl font-semibold\">\r\n {t(\"title\", \"Sign In\")}\r\n </h1>\r\n <p className=\"text-sm text-muted-foreground\">\r\n {t(\"subtitle\", \"Welcome back! Sign in to continue\")}\r\n </p>\r\n </div>\r\n\r\n {error && (\r\n <div className=\"mt-4 p-3 text-sm text-red-600 bg-red-50 dark:bg-red-950 dark:text-red-400 rounded-md\">\r\n {error}\r\n </div>\r\n )}\r\n\r\n <div className=\"mt-6 space-y-6\">\r\n <div className=\"space-y-2\">\r\n <Label htmlFor=\"username\" className=\"block text-sm\">\r\n {t(\"username\", \"Username\")}\r\n </Label>\r\n <Input\r\n type=\"text\"\r\n required\r\n name=\"username\"\r\n id=\"username\"\r\n autoComplete=\"username\"\r\n value={username}\r\n onChange={(e) => setUsername(e.target.value)}\r\n placeholder={t(\"usernamePlaceholder\", \"Enter your username\")}\r\n disabled={isLoading}\r\n />\r\n </div>\r\n\r\n <div className=\"space-y-2\">\r\n <div className=\"flex items-center justify-between\">\r\n <Label htmlFor=\"password\" className=\"text-sm\">\r\n {t(\"password\", \"Password\")}\r\n </Label>\r\n <Button asChild variant=\"link\" size=\"sm\" className=\"h-auto p-0\">\r\n <Link to=\"/forgot-password\" className=\"text-xs\">\r\n {t(\"forgotPassword\", \"Forgot password?\")}\r\n </Link>\r\n </Button>\r\n </div>\r\n <Input\r\n type=\"password\"\r\n required\r\n name=\"password\"\r\n id=\"password\"\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n placeholder=\"••••••••\"\r\n disabled={isLoading}\r\n />\r\n </div>\r\n\r\n <Button type=\"submit\" className=\"w-full\" disabled={isLoading}>\r\n {isLoading ? (\r\n <>\r\n <div className=\"w-4 h-4 border-2 border-primary-foreground border-t-transparent rounded-full animate-spin mr-2\" />\r\n {t(\"signingIn\", \"Signing in...\")}\r\n </>\r\n ) : (\r\n t(\"signIn\", \"Sign In\")\r\n )}\r\n </Button>\r\n </div>\r\n </div>\r\n\r\n <div className=\"p-3\">\r\n <p className=\"text-center text-sm text-muted-foreground\">\r\n {t(\"noAccount\", \"Don't have an account?\")}\r\n <Button asChild variant=\"link\" className=\"px-2\">\r\n <Link to=\"/register\">{t(\"createAccount\", \"Create account\")}</Link>\r\n </Button>\r\n </p>\r\n </div>\r\n </form>\r\n </section>\r\n );\r\n}\r\n\r\nexport default LoginPage;\r\n"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
"path": "login-page/lang/en.json",
|
|
30
30
|
"type": "registry:lang",
|
|
31
31
|
"target": "$modules$/login-page/lang/en.json",
|
|
32
|
-
"content": "{\n \"title\": \"Sign In\",\n \"subtitle\": \"Welcome back! Sign in to continue\",\n \"username\": \"Username\",\n \"usernamePlaceholder\": \"Enter your username\",\n \"email\": \"Email\",\n \"emailPlaceholder\": \"you@example.com\",\n \"password\": \"Password\",\n \"forgotPassword\": \"Forgot password?\",\n \"signIn\": \"Sign In\",\n \"signingIn\": \"Signing in...\",\n \"noAccount\": \"Don't have an account?\",\n \"createAccount\": \"Create account\",\n \"loginSuccess\": \"Login successful!\",\n \"loginError\": \"Login failed. Please check your credentials.\"\n}\n"
|
|
32
|
+
"content": "{\r\n \"title\": \"Sign In\",\r\n \"subtitle\": \"Welcome back! Sign in to continue\",\r\n \"username\": \"Username\",\r\n \"usernamePlaceholder\": \"Enter your username\",\r\n \"email\": \"Email\",\r\n \"emailPlaceholder\": \"you@example.com\",\r\n \"password\": \"Password\",\r\n \"forgotPassword\": \"Forgot password?\",\r\n \"signIn\": \"Sign In\",\r\n \"signingIn\": \"Signing in...\",\r\n \"noAccount\": \"Don't have an account?\",\r\n \"createAccount\": \"Create account\",\r\n \"loginSuccess\": \"Login successful!\",\r\n \"loginError\": \"Login failed. Please check your credentials.\"\r\n}\r\n"
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
"path": "login-page/lang/tr.json",
|
|
36
36
|
"type": "registry:lang",
|
|
37
37
|
"target": "$modules$/login-page/lang/tr.json",
|
|
38
|
-
"content": "{\n \"title\": \"Giriş Yap\",\n \"subtitle\": \"Tekrar hoş geldiniz! Devam etmek için giriş yapın\",\n \"username\": \"Kullanıcı Adı\",\n \"usernamePlaceholder\": \"Kullanıcı adınızı girin\",\n \"email\": \"E-posta\",\n \"emailPlaceholder\": \"ornek@email.com\",\n \"password\": \"Şifre\",\n \"forgotPassword\": \"Şifremi unuttum\",\n \"signIn\": \"Giriş Yap\",\n \"signingIn\": \"Giriş yapılıyor...\",\n \"noAccount\": \"Hesabınız yok mu?\",\n \"createAccount\": \"Hesap oluştur\",\n \"loginSuccess\": \"Giriş başarılı!\",\n \"loginError\": \"Giriş başarısız. Lütfen bilgilerinizi kontrol edin.\"\n}\n"
|
|
38
|
+
"content": "{\r\n \"title\": \"Giriş Yap\",\r\n \"subtitle\": \"Tekrar hoş geldiniz! Devam etmek için giriş yapın\",\r\n \"username\": \"Kullanıcı Adı\",\r\n \"usernamePlaceholder\": \"Kullanıcı adınızı girin\",\r\n \"email\": \"E-posta\",\r\n \"emailPlaceholder\": \"ornek@email.com\",\r\n \"password\": \"Şifre\",\r\n \"forgotPassword\": \"Şifremi unuttum\",\r\n \"signIn\": \"Giriş Yap\",\r\n \"signingIn\": \"Giriş yapılıyor...\",\r\n \"noAccount\": \"Hesabınız yok mu?\",\r\n \"createAccount\": \"Hesap oluştur\",\r\n \"loginSuccess\": \"Giriş başarılı!\",\r\n \"loginError\": \"Giriş başarısız. Lütfen bilgilerinizi kontrol edin.\"\r\n}\r\n"
|
|
39
39
|
}
|
|
40
40
|
],
|
|
41
41
|
"exports": {
|
|
@@ -11,25 +11,25 @@
|
|
|
11
11
|
"path": "logo-cloud/logo-cloud.tsx",
|
|
12
12
|
"type": "registry:component",
|
|
13
13
|
"target": "$modules$/logo-cloud/logo-cloud.tsx",
|
|
14
|
-
"content": "\"use client\";\n\nimport { useTranslation } from \"react-i18next\";\nimport { cn } from \"@/lib/utils\";\n\ninterface Logo {\n name: string;\n image: string;\n url?: string;\n}\n\ninterface LogoCloudProps {\n logos?: Logo[];\n title?: string;\n grayscale?: boolean;\n animate?: boolean;\n speed?: \"slow\" | \"normal\" | \"fast\";\n pauseOnHover?: boolean;\n className?: string;\n}\n\nconst defaultLogos: Logo[] = [\n { name: \"Company 1\", image: \"/images/placeholder.png\" },\n { name: \"Company 2\", image: \"/images/placeholder.png\" },\n { name: \"Company 3\", image: \"/images/placeholder.png\" },\n { name: \"Company 4\", image: \"/images/placeholder.png\" },\n { name: \"Company 5\", image: \"/images/placeholder.png\" },\n { name: \"Company 6\", image: \"/images/placeholder.png\" },\n];\n\nconst speedDuration = {\n slow: \"40s\",\n normal: \"25s\",\n fast: \"15s\",\n};\n\nexport function LogoCloud({\n logos = defaultLogos,\n title,\n grayscale = true,\n animate = true,\n speed = \"slow\",\n pauseOnHover = true,\n className,\n}: LogoCloudProps) {\n const { t } = useTranslation(\"logo-cloud\");\n\n const displayTitle = title ?? t(\"title\");\n\n const renderLogo = (logo: Logo, index: number) => {\n const imageElement = (\n <img\n src={logo.image}\n alt={logo.name}\n className={cn(\n \"h-10 md:h-12 w-auto object-contain transition-all duration-300 rounded-[var(--radius)]\",\n grayscale && \"grayscale opacity-60 hover:grayscale-0 hover:opacity-100\"\n )}\n draggable={false}\n />\n );\n\n if (logo.url) {\n return (\n <a\n key={index}\n href={logo.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex items-center justify-center px-8 md:px-12 shrink-0\"\n >\n {imageElement}\n </a>\n );\n }\n\n return (\n <div key={index} className=\"flex items-center justify-center px-8 md:px-12 shrink-0\">\n {imageElement}\n </div>\n );\n };\n\n return (\n <section className={cn(\"py-12 md:py-16 overflow-hidden\", className)}>\n <div className=\"container max-w-[var(--container-max-width)] mx-auto px-4\">\n {displayTitle && (\n <p className=\"text-center text-sm font-medium text-muted-foreground uppercase tracking-wider mb-8\">\n {displayTitle}\n </p>\n )}\n </div>\n\n {/* Marquee Container */}\n <div\n className={cn(\n \"relative w-full\",\n pauseOnHover && \"[&:hover_.marquee-content]:pause\"\n )}\n >\n {/* Gradient Masks */}\n <div className=\"absolute left-0 top-0 bottom-0 w-20 md:w-32 bg-gradient-to-r from-background to-transparent z-10 pointer-events-none\" />\n <div className=\"absolute right-0 top-0 bottom-0 w-20 md:w-32 bg-gradient-to-l from-background to-transparent z-10 pointer-events-none\" />\n\n {/* Scrolling Content */}\n <div className=\"flex overflow-hidden\">\n <div\n className={cn(\n \"marquee-content flex items-center\",\n animate && \"animate-marquee\"\n )}\n style={{\n [\"--marquee-duration\" as string]: speedDuration[speed],\n }}\n >\n {/* First set of logos */}\n {logos.map((logo, index) => renderLogo(logo, index))}\n {/* Duplicate for seamless loop */}\n {logos.map((logo, index) => renderLogo(logo, index + logos.length))}\n </div>\n </div>\n </div>\n\n <style>{`\n @keyframes marquee {\n 0% {\n transform: translateX(0);\n }\n 100% {\n transform: translateX(-50%);\n }\n }\n .animate-marquee {\n animation: marquee var(--marquee-duration, 25s) linear infinite;\n }\n .pause {\n animation-play-state: paused !important;\n }\n `}</style>\n </section>\n );\n}\n"
|
|
14
|
+
"content": "\"use client\";\r\n\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { cn } from \"@/lib/utils\";\r\n\r\ninterface Logo {\r\n name: string;\r\n image: string;\r\n url?: string;\r\n}\r\n\r\ninterface LogoCloudProps {\r\n logos?: Logo[];\r\n title?: string;\r\n grayscale?: boolean;\r\n animate?: boolean;\r\n speed?: \"slow\" | \"normal\" | \"fast\";\r\n pauseOnHover?: boolean;\r\n className?: string;\r\n}\r\n\r\nconst defaultLogos: Logo[] = [\r\n { name: \"Company 1\", image: \"/images/placeholder.png\" },\r\n { name: \"Company 2\", image: \"/images/placeholder.png\" },\r\n { name: \"Company 3\", image: \"/images/placeholder.png\" },\r\n { name: \"Company 4\", image: \"/images/placeholder.png\" },\r\n { name: \"Company 5\", image: \"/images/placeholder.png\" },\r\n { name: \"Company 6\", image: \"/images/placeholder.png\" },\r\n];\r\n\r\nconst speedDuration = {\r\n slow: \"40s\",\r\n normal: \"25s\",\r\n fast: \"15s\",\r\n};\r\n\r\nexport function LogoCloud({\r\n logos = defaultLogos,\r\n title,\r\n grayscale = true,\r\n animate = true,\r\n speed = \"slow\",\r\n pauseOnHover = true,\r\n className,\r\n}: LogoCloudProps) {\r\n const { t } = useTranslation(\"logo-cloud\");\r\n\r\n const displayTitle = title ?? t(\"title\");\r\n\r\n const renderLogo = (logo: Logo, index: number) => {\r\n const imageElement = (\r\n <img\r\n src={logo.image}\r\n alt={logo.name}\r\n className={cn(\r\n \"h-10 md:h-12 w-auto object-contain transition-all duration-300 rounded-[var(--radius)]\",\r\n grayscale && \"grayscale opacity-60 hover:grayscale-0 hover:opacity-100\"\r\n )}\r\n draggable={false}\r\n />\r\n );\r\n\r\n if (logo.url) {\r\n return (\r\n <a\r\n key={index}\r\n href={logo.url}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"flex items-center justify-center px-8 md:px-12 shrink-0\"\r\n >\r\n {imageElement}\r\n </a>\r\n );\r\n }\r\n\r\n return (\r\n <div key={index} className=\"flex items-center justify-center px-8 md:px-12 shrink-0\">\r\n {imageElement}\r\n </div>\r\n );\r\n };\r\n\r\n return (\r\n <section className={cn(\"py-12 md:py-16 overflow-hidden\", className)}>\r\n <div className=\"container max-w-[var(--container-max-width)] mx-auto px-4\">\r\n {displayTitle && (\r\n <p className=\"text-center text-sm font-medium text-muted-foreground uppercase tracking-wider mb-8\">\r\n {displayTitle}\r\n </p>\r\n )}\r\n </div>\r\n\r\n {/* Marquee Container */}\r\n <div\r\n className={cn(\r\n \"relative w-full\",\r\n pauseOnHover && \"[&:hover_.marquee-content]:pause\"\r\n )}\r\n >\r\n {/* Gradient Masks */}\r\n <div className=\"absolute left-0 top-0 bottom-0 w-20 md:w-32 bg-gradient-to-r from-background to-transparent z-10 pointer-events-none\" />\r\n <div className=\"absolute right-0 top-0 bottom-0 w-20 md:w-32 bg-gradient-to-l from-background to-transparent z-10 pointer-events-none\" />\r\n\r\n {/* Scrolling Content */}\r\n <div className=\"flex overflow-hidden\">\r\n <div\r\n className={cn(\r\n \"marquee-content flex items-center\",\r\n animate && \"animate-marquee\"\r\n )}\r\n style={{\r\n [\"--marquee-duration\" as string]: speedDuration[speed],\r\n }}\r\n >\r\n {/* First set of logos */}\r\n {logos.map((logo, index) => renderLogo(logo, index))}\r\n {/* Duplicate for seamless loop */}\r\n {logos.map((logo, index) => renderLogo(logo, index + logos.length))}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <style>{`\r\n @keyframes marquee {\r\n 0% {\r\n transform: translateX(0);\r\n }\r\n 100% {\r\n transform: translateX(-50%);\r\n }\r\n }\r\n .animate-marquee {\r\n animation: marquee var(--marquee-duration, 25s) linear infinite;\r\n }\r\n .pause {\r\n animation-play-state: paused !important;\r\n }\r\n `}</style>\r\n </section>\r\n );\r\n}\r\n"
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
17
|
"path": "logo-cloud/index.ts",
|
|
18
18
|
"type": "registry:index",
|
|
19
19
|
"target": "$modules$/logo-cloud/index.ts",
|
|
20
|
-
"content": "export * from \"./logo-cloud\";\n"
|
|
20
|
+
"content": "export * from \"./logo-cloud\";\r\n"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
"path": "logo-cloud/lang/en.json",
|
|
24
24
|
"type": "registry:lang",
|
|
25
25
|
"target": "$modules$/logo-cloud/lang/en.json",
|
|
26
|
-
"content": "{\n \"title\": \"Trusted by leading companies\"\n}\n"
|
|
26
|
+
"content": "{\r\n \"title\": \"Trusted by leading companies\"\r\n}\r\n"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
"path": "logo-cloud/lang/tr.json",
|
|
30
30
|
"type": "registry:lang",
|
|
31
31
|
"target": "$modules$/logo-cloud/lang/tr.json",
|
|
32
|
-
"content": "{\n \"title\": \"Önde gelen şirketler tarafından tercih ediliyor\"\n}\n"
|
|
32
|
+
"content": "{\r\n \"title\": \"Önde gelen şirketler tarafından tercih ediliyor\"\r\n}\r\n"
|
|
33
33
|
}
|
|
34
34
|
],
|
|
35
35
|
"exports": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"path": "masonry-grid/index.ts",
|
|
14
14
|
"type": "registry:index",
|
|
15
15
|
"target": "$modules$/masonry-grid/index.ts",
|
|
16
|
-
"content": "export { MasonryGrid } from \"./masonry-grid\";\n"
|
|
16
|
+
"content": "export { MasonryGrid } from \"./masonry-grid\";\r\n"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"path": "masonry-grid/masonry-grid.tsx",
|
|
@@ -25,13 +25,13 @@
|
|
|
25
25
|
"path": "masonry-grid/lang/en.json",
|
|
26
26
|
"type": "registry:lang",
|
|
27
27
|
"target": "$modules$/masonry-grid/lang/en.json",
|
|
28
|
-
"content": "{\n \"close\": \"Close\"\n}\n"
|
|
28
|
+
"content": "{\r\n \"close\": \"Close\"\r\n}\r\n"
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
"path": "masonry-grid/lang/tr.json",
|
|
32
32
|
"type": "registry:lang",
|
|
33
33
|
"target": "$modules$/masonry-grid/lang/tr.json",
|
|
34
|
-
"content": "{\n \"close\": \"Kapat\"\n}\n"
|
|
34
|
+
"content": "{\r\n \"close\": \"Kapat\"\r\n}\r\n"
|
|
35
35
|
}
|
|
36
36
|
],
|
|
37
37
|
"exports": {
|
|
@@ -21,25 +21,25 @@
|
|
|
21
21
|
"path": "my-orders-page/index.ts",
|
|
22
22
|
"type": "registry:index",
|
|
23
23
|
"target": "$modules$/my-orders-page/index.ts",
|
|
24
|
-
"content": "export * from \"./my-orders-page\";\nexport { default } from \"./my-orders-page\";\n"
|
|
24
|
+
"content": "export * from \"./my-orders-page\";\r\nexport { default } from \"./my-orders-page\";\r\n"
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
"path": "my-orders-page/my-orders-page.tsx",
|
|
28
28
|
"type": "registry:page",
|
|
29
29
|
"target": "$modules$/my-orders-page/my-orders-page.tsx",
|
|
30
|
-
"content": "import { useEffect, useState } from \"react\";\nimport { Link } from \"react-router\";\nimport { toast } from \"sonner\";\nimport {\n Package,\n Loader2,\n ShoppingBag,\n ArrowLeft,\n Calendar,\n CreditCard,\n Truck,\n CheckCircle2,\n Clock,\n XCircle,\n} from \"lucide-react\";\nimport { Layout } from \"@/components/Layout\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent } from \"@/components/ui/card\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { usePageTitle } from \"@/hooks/use-page-title\";\nimport { useTranslation } from \"react-i18next\";\nimport { useAuth } from \"@/modules/auth-core\";\nimport { customerClient } from \"@/modules/api\";\n\ninterface OrderItem {\n name: string;\n description?: string;\n quantity: number;\n amount: number;\n img?: string;\n}\n\ninterface Order {\n id: string;\n created_at: string;\n status: string;\n payment_status: string;\n total_amount: number;\n currency: string;\n product_data?: OrderItem[];\n}\n\ntype PageStatus = \"loading\" | \"success\" | \"error\" | \"unauthorized\";\n\nexport function MyOrdersPage() {\n const { t } = useTranslation(\"my-orders-page\");\n usePageTitle({ title: t(\"title\", \"My Orders\") });\n\n const { isAuthenticated, token } = useAuth();\n\n const [status, setStatus] = useState<PageStatus>(\"loading\");\n const [orders, setOrders] = useState<Order[]>([]);\n\n useEffect(() => {\n if (!isAuthenticated || !token) {\n setStatus(\"unauthorized\");\n return;\n }\n\n const fetchOrders = async () => {\n try {\n const response = (await (customerClient as any).orders.getMyOrders()) as any;\n // Handle both 'orders' and 'transactions' keys from API\n const ordersList = response.orders || response.transactions || [];\n setOrders(ordersList);\n setStatus(\"success\");\n } catch (error: any) {\n console.error(\"Error fetching orders:\", error);\n\n if (error?.response?.status === 401) {\n setStatus(\"unauthorized\");\n } else {\n setStatus(\"error\");\n toast.error(t(\"loadError\", \"Failed to load orders. Please try again.\"));\n }\n }\n };\n\n fetchOrders();\n }, [isAuthenticated, token, t]);\n\n const getStatusIcon = (orderStatus: string) => {\n const statusLower = orderStatus.toLowerCase();\n if ([\"paid\", \"completed\", \"tamamlandı\"].includes(statusLower)) {\n return <CheckCircle2 className=\"w-4 h-4\" />;\n }\n if ([\"processing\", \"hazırlanıyor\"].includes(statusLower)) {\n return <Clock className=\"w-4 h-4\" />;\n }\n if ([\"shipped\", \"kargoda\"].includes(statusLower)) {\n return <Truck className=\"w-4 h-4\" />;\n }\n if ([\"cancelled\", \"iptal\", \"failed\"].includes(statusLower)) {\n return <XCircle className=\"w-4 h-4\" />;\n }\n return <Package className=\"w-4 h-4\" />;\n };\n\n const getStatusBadgeVariant = (\n orderStatus: string\n ): \"default\" | \"secondary\" | \"destructive\" | \"outline\" => {\n const statusLower = orderStatus.toLowerCase();\n if ([\"paid\", \"completed\", \"tamamlandı\"].includes(statusLower)) {\n return \"default\";\n }\n if ([\"processing\", \"hazırlanıyor\"].includes(statusLower)) {\n return \"secondary\";\n }\n if ([\"shipped\", \"kargoda\"].includes(statusLower)) {\n return \"outline\";\n }\n if ([\"cancelled\", \"iptal\", \"failed\"].includes(statusLower)) {\n return \"destructive\";\n }\n return \"secondary\";\n };\n\n const getPaymentStatusBadge = (\n paymentStatus: string\n ): \"default\" | \"secondary\" | \"destructive\" => {\n if (paymentStatus === \"paid\") return \"default\";\n if (paymentStatus === \"unpaid\" || paymentStatus === \"pending\")\n return \"secondary\";\n return \"destructive\";\n };\n\n const formatDate = (dateString: string) => {\n try {\n return new Date(dateString).toLocaleDateString(undefined, {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n } catch {\n return dateString;\n }\n };\n\n const formatCurrency = (amount: number, currency: string) => {\n return new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: currency.toUpperCase(),\n }).format(amount / 100);\n };\n\n // Unauthorized\n if (status === \"unauthorized\") {\n return (\n <Layout>\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-16\">\n <div className=\"max-w-md mx-auto text-center\">\n <Card>\n <CardContent className=\"pt-8 pb-8\">\n <Package className=\"w-16 h-16 text-muted-foreground mx-auto mb-4\" />\n <h1 className=\"text-2xl font-bold mb-2\">\n {t(\"loginRequired\", \"Login Required\")}\n </h1>\n <p className=\"text-muted-foreground mb-6\">\n {t(\n \"loginRequiredDescription\",\n \"Please login to view your orders.\"\n )}\n </p>\n <div className=\"flex flex-col gap-3\">\n <Button asChild>\n <Link to=\"/login\">{t(\"login\", \"Login\")}</Link>\n </Button>\n <Button variant=\"outline\" asChild>\n <Link to=\"/register\">\n {t(\"createAccount\", \"Create Account\")}\n </Link>\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n </div>\n </Layout>\n );\n }\n\n // Loading\n if (status === \"loading\") {\n return (\n <Layout>\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-16\">\n <div className=\"max-w-md mx-auto text-center\">\n <Card>\n <CardContent className=\"pt-8 pb-8\">\n <Loader2 className=\"w-16 h-16 text-primary mx-auto mb-4 animate-spin\" />\n <h1 className=\"text-2xl font-bold mb-2\">\n {t(\"loadingOrders\", \"Loading Orders\")}\n </h1>\n <p className=\"text-muted-foreground\">\n {t(\"pleaseWait\", \"Please wait...\")}\n </p>\n </CardContent>\n </Card>\n </div>\n </div>\n </Layout>\n );\n }\n\n // Error\n if (status === \"error\") {\n return (\n <Layout>\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-16\">\n <div className=\"max-w-md mx-auto text-center\">\n <Card>\n <CardContent className=\"pt-8 pb-8\">\n <Package className=\"w-16 h-16 text-red-500 mx-auto mb-4\" />\n <h1 className=\"text-2xl font-bold mb-2\">\n {t(\"errorTitle\", \"Something went wrong\")}\n </h1>\n <p className=\"text-muted-foreground mb-6\">\n {t(\n \"errorDescription\",\n \"We couldn't load your orders. Please try again.\"\n )}\n </p>\n <Button onClick={() => window.location.reload()}>\n {t(\"tryAgain\", \"Try Again\")}\n </Button>\n </CardContent>\n </Card>\n </div>\n </div>\n </Layout>\n );\n }\n\n // No orders\n if (orders.length === 0) {\n return (\n <Layout>\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-16\">\n <div className=\"max-w-md mx-auto text-center\">\n <Card>\n <CardContent className=\"pt-8 pb-8\">\n <Package className=\"w-16 h-16 text-muted-foreground mx-auto mb-4\" />\n <h1 className=\"text-2xl font-bold mb-2\">\n {t(\"noOrders\", \"No Orders Yet\")}\n </h1>\n <p className=\"text-muted-foreground mb-6\">\n {t(\n \"noOrdersDescription\",\n \"You haven't placed any orders yet. Start shopping to see your orders here.\"\n )}\n </p>\n <Button asChild>\n <Link to=\"/products\">\n <ShoppingBag className=\"w-4 h-4 mr-2\" />\n {t(\"startShopping\", \"Start Shopping\")}\n </Link>\n </Button>\n </CardContent>\n </Card>\n </div>\n </div>\n </Layout>\n );\n }\n\n // Success - Has orders\n return (\n <Layout>\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-8\">\n {/* Header */}\n <div className=\"flex items-center gap-4 mb-8\">\n <Button variant=\"ghost\" size=\"icon\" asChild>\n <Link to=\"/\">\n <ArrowLeft className=\"h-4 w-4\" />\n </Link>\n </Button>\n <div>\n <h1 className=\"text-3xl font-bold\">{t(\"title\", \"My Orders\")}</h1>\n <p className=\"text-muted-foreground\">\n {t(\"orderCount\", \"{{count}} order(s)\", { count: orders.length })}\n </p>\n </div>\n </div>\n\n {/* Orders List */}\n <div className=\"space-y-6\">\n {orders.map((order) => (\n <Card key={order.id} className=\"overflow-hidden\">\n {/* Order Header */}\n <div className=\"bg-muted/50 px-6 py-4 border-b\">\n <div className=\"flex flex-col md:flex-row md:items-center md:justify-between gap-4\">\n <div className=\"flex flex-wrap items-center gap-x-6 gap-y-2 text-sm\">\n <div>\n <span className=\"text-muted-foreground\">\n {t(\"orderNumber\", \"Order\")}:\n </span>{\" \"}\n <span className=\"font-mono font-medium\">\n #{order.id.slice(0, 8)}\n </span>\n </div>\n <div className=\"flex items-center gap-1.5 text-muted-foreground\">\n <Calendar className=\"w-4 h-4\" />\n <span>{formatDate(order.created_at)}</span>\n </div>\n <div className=\"flex items-center gap-1.5 text-muted-foreground\">\n <CreditCard className=\"w-4 h-4\" />\n <Badge\n variant={getPaymentStatusBadge(order.payment_status)}\n className=\"text-xs\"\n >\n {order.payment_status === \"paid\"\n ? t(\"paid\", \"Paid\")\n : t(\"unpaid\", \"Unpaid\")}\n </Badge>\n </div>\n </div>\n <div className=\"flex items-center gap-3\">\n <Badge\n variant={getStatusBadgeVariant(order.status)}\n className=\"flex items-center gap-1.5\"\n >\n {getStatusIcon(order.status)}\n <span className=\"capitalize\">{order.status}</span>\n </Badge>\n </div>\n </div>\n </div>\n\n {/* Order Items */}\n <CardContent className=\"p-6\">\n <div className=\"space-y-4\">\n {order.product_data?.map((item, index) => (\n <div\n key={index}\n className=\"flex gap-4 pb-4 last:pb-0 last:border-0 border-b border-border/50\"\n >\n {/* Product Image */}\n <div className=\"flex-shrink-0\">\n <img\n src={item.img || \"/images/placeholder.png\"}\n alt={item.name}\n className=\"w-20 h-20 md:w-24 md:h-24 object-cover rounded-lg border\"\n onError={(e) => {\n (e.target as HTMLImageElement).src =\n \"/images/placeholder.png\";\n }}\n />\n </div>\n\n {/* Product Details */}\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"font-semibold text-base md:text-lg truncate\">\n {item.name}\n </h3>\n {item.description && (\n <p className=\"text-sm text-muted-foreground line-clamp-2 mt-1\">\n {item.description}\n </p>\n )}\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1 mt-2 text-sm\">\n <span className=\"text-muted-foreground\">\n {t(\"quantity\", \"Qty\")}:{\" \"}\n <span className=\"font-medium text-foreground\">\n {item.quantity}\n </span>\n </span>\n <span className=\"font-semibold text-foreground\">\n {formatCurrency(item.amount, order.currency)}\n </span>\n </div>\n </div>\n </div>\n ))}\n </div>\n\n {/* Order Total */}\n <div className=\"flex items-center justify-between mt-6 pt-4 border-t\">\n <span className=\"text-muted-foreground\">\n {t(\"total\", \"Total\")}\n </span>\n <span className=\"text-xl font-bold\">\n {formatCurrency(order.total_amount, order.currency)}\n </span>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n\n {/* Continue Shopping */}\n <div className=\"mt-8 text-center\">\n <Button variant=\"outline\" asChild>\n <Link to=\"/products\">\n <ShoppingBag className=\"w-4 h-4 mr-2\" />\n {t(\"continueShopping\", \"Continue Shopping\")}\n </Link>\n </Button>\n </div>\n </div>\n </Layout>\n );\n}\n\nexport default MyOrdersPage;\n"
|
|
30
|
+
"content": "import { useEffect, useState } from \"react\";\r\nimport { Link } from \"react-router\";\r\nimport { toast } from \"sonner\";\r\nimport {\r\n Package,\r\n Loader2,\r\n ShoppingBag,\r\n ArrowLeft,\r\n Calendar,\r\n CreditCard,\r\n Truck,\r\n CheckCircle2,\r\n Clock,\r\n XCircle,\r\n} from \"lucide-react\";\r\nimport { Layout } from \"@/components/Layout\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Card, CardContent } from \"@/components/ui/card\";\r\nimport { Badge } from \"@/components/ui/badge\";\r\nimport { usePageTitle } from \"@/hooks/use-page-title\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { useAuth } from \"@/modules/auth-core\";\r\nimport { customerClient } from \"@/modules/api\";\r\n\r\ninterface OrderItem {\r\n name: string;\r\n description?: string;\r\n quantity: number;\r\n amount: number;\r\n img?: string;\r\n}\r\n\r\ninterface Order {\r\n id: string;\r\n created_at: string;\r\n status: string;\r\n payment_status: string;\r\n total_amount: number;\r\n currency: string;\r\n product_data?: OrderItem[];\r\n}\r\n\r\ntype PageStatus = \"loading\" | \"success\" | \"error\" | \"unauthorized\";\r\n\r\nexport function MyOrdersPage() {\r\n const { t } = useTranslation(\"my-orders-page\");\r\n usePageTitle({ title: t(\"title\", \"My Orders\") });\r\n\r\n const { isAuthenticated, token } = useAuth();\r\n\r\n const [status, setStatus] = useState<PageStatus>(\"loading\");\r\n const [orders, setOrders] = useState<Order[]>([]);\r\n\r\n useEffect(() => {\r\n if (!isAuthenticated || !token) {\r\n setStatus(\"unauthorized\");\r\n return;\r\n }\r\n\r\n const fetchOrders = async () => {\r\n try {\r\n const response = (await (customerClient as any).orders.getMyOrders()) as any;\r\n // Handle both 'orders' and 'transactions' keys from API\r\n const ordersList = response.orders || response.transactions || [];\r\n setOrders(ordersList);\r\n setStatus(\"success\");\r\n } catch (error: any) {\r\n console.error(\"Error fetching orders:\", error);\r\n\r\n if (error?.response?.status === 401) {\r\n setStatus(\"unauthorized\");\r\n } else {\r\n setStatus(\"error\");\r\n toast.error(t(\"loadError\", \"Failed to load orders. Please try again.\"));\r\n }\r\n }\r\n };\r\n\r\n fetchOrders();\r\n }, [isAuthenticated, token, t]);\r\n\r\n const getStatusIcon = (orderStatus: string) => {\r\n const statusLower = orderStatus.toLowerCase();\r\n if ([\"paid\", \"completed\", \"tamamlandı\"].includes(statusLower)) {\r\n return <CheckCircle2 className=\"w-4 h-4\" />;\r\n }\r\n if ([\"processing\", \"hazırlanıyor\"].includes(statusLower)) {\r\n return <Clock className=\"w-4 h-4\" />;\r\n }\r\n if ([\"shipped\", \"kargoda\"].includes(statusLower)) {\r\n return <Truck className=\"w-4 h-4\" />;\r\n }\r\n if ([\"cancelled\", \"iptal\", \"failed\"].includes(statusLower)) {\r\n return <XCircle className=\"w-4 h-4\" />;\r\n }\r\n return <Package className=\"w-4 h-4\" />;\r\n };\r\n\r\n const getStatusBadgeVariant = (\r\n orderStatus: string\r\n ): \"default\" | \"secondary\" | \"destructive\" | \"outline\" => {\r\n const statusLower = orderStatus.toLowerCase();\r\n if ([\"paid\", \"completed\", \"tamamlandı\"].includes(statusLower)) {\r\n return \"default\";\r\n }\r\n if ([\"processing\", \"hazırlanıyor\"].includes(statusLower)) {\r\n return \"secondary\";\r\n }\r\n if ([\"shipped\", \"kargoda\"].includes(statusLower)) {\r\n return \"outline\";\r\n }\r\n if ([\"cancelled\", \"iptal\", \"failed\"].includes(statusLower)) {\r\n return \"destructive\";\r\n }\r\n return \"secondary\";\r\n };\r\n\r\n const getPaymentStatusBadge = (\r\n paymentStatus: string\r\n ): \"default\" | \"secondary\" | \"destructive\" => {\r\n if (paymentStatus === \"paid\") return \"default\";\r\n if (paymentStatus === \"unpaid\" || paymentStatus === \"pending\")\r\n return \"secondary\";\r\n return \"destructive\";\r\n };\r\n\r\n const formatDate = (dateString: string) => {\r\n try {\r\n return new Date(dateString).toLocaleDateString(undefined, {\r\n year: \"numeric\",\r\n month: \"long\",\r\n day: \"numeric\",\r\n hour: \"2-digit\",\r\n minute: \"2-digit\",\r\n });\r\n } catch {\r\n return dateString;\r\n }\r\n };\r\n\r\n const formatCurrency = (amount: number, currency: string) => {\r\n return new Intl.NumberFormat(\"en-US\", {\r\n style: \"currency\",\r\n currency: currency.toUpperCase(),\r\n }).format(amount / 100);\r\n };\r\n\r\n // Unauthorized\r\n if (status === \"unauthorized\") {\r\n return (\r\n <Layout>\r\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-16\">\r\n <div className=\"max-w-md mx-auto text-center\">\r\n <Card>\r\n <CardContent className=\"pt-8 pb-8\">\r\n <Package className=\"w-16 h-16 text-muted-foreground mx-auto mb-4\" />\r\n <h1 className=\"text-2xl font-bold mb-2\">\r\n {t(\"loginRequired\", \"Login Required\")}\r\n </h1>\r\n <p className=\"text-muted-foreground mb-6\">\r\n {t(\r\n \"loginRequiredDescription\",\r\n \"Please login to view your orders.\"\r\n )}\r\n </p>\r\n <div className=\"flex flex-col gap-3\">\r\n <Button asChild>\r\n <Link to=\"/login\">{t(\"login\", \"Login\")}</Link>\r\n </Button>\r\n <Button variant=\"outline\" asChild>\r\n <Link to=\"/register\">\r\n {t(\"createAccount\", \"Create Account\")}\r\n </Link>\r\n </Button>\r\n </div>\r\n </CardContent>\r\n </Card>\r\n </div>\r\n </div>\r\n </Layout>\r\n );\r\n }\r\n\r\n // Loading\r\n if (status === \"loading\") {\r\n return (\r\n <Layout>\r\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-16\">\r\n <div className=\"max-w-md mx-auto text-center\">\r\n <Card>\r\n <CardContent className=\"pt-8 pb-8\">\r\n <Loader2 className=\"w-16 h-16 text-primary mx-auto mb-4 animate-spin\" />\r\n <h1 className=\"text-2xl font-bold mb-2\">\r\n {t(\"loadingOrders\", \"Loading Orders\")}\r\n </h1>\r\n <p className=\"text-muted-foreground\">\r\n {t(\"pleaseWait\", \"Please wait...\")}\r\n </p>\r\n </CardContent>\r\n </Card>\r\n </div>\r\n </div>\r\n </Layout>\r\n );\r\n }\r\n\r\n // Error\r\n if (status === \"error\") {\r\n return (\r\n <Layout>\r\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-16\">\r\n <div className=\"max-w-md mx-auto text-center\">\r\n <Card>\r\n <CardContent className=\"pt-8 pb-8\">\r\n <Package className=\"w-16 h-16 text-red-500 mx-auto mb-4\" />\r\n <h1 className=\"text-2xl font-bold mb-2\">\r\n {t(\"errorTitle\", \"Something went wrong\")}\r\n </h1>\r\n <p className=\"text-muted-foreground mb-6\">\r\n {t(\r\n \"errorDescription\",\r\n \"We couldn't load your orders. Please try again.\"\r\n )}\r\n </p>\r\n <Button onClick={() => window.location.reload()}>\r\n {t(\"tryAgain\", \"Try Again\")}\r\n </Button>\r\n </CardContent>\r\n </Card>\r\n </div>\r\n </div>\r\n </Layout>\r\n );\r\n }\r\n\r\n // No orders\r\n if (orders.length === 0) {\r\n return (\r\n <Layout>\r\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-16\">\r\n <div className=\"max-w-md mx-auto text-center\">\r\n <Card>\r\n <CardContent className=\"pt-8 pb-8\">\r\n <Package className=\"w-16 h-16 text-muted-foreground mx-auto mb-4\" />\r\n <h1 className=\"text-2xl font-bold mb-2\">\r\n {t(\"noOrders\", \"No Orders Yet\")}\r\n </h1>\r\n <p className=\"text-muted-foreground mb-6\">\r\n {t(\r\n \"noOrdersDescription\",\r\n \"You haven't placed any orders yet. Start shopping to see your orders here.\"\r\n )}\r\n </p>\r\n <Button asChild>\r\n <Link to=\"/products\">\r\n <ShoppingBag className=\"w-4 h-4 mr-2\" />\r\n {t(\"startShopping\", \"Start Shopping\")}\r\n </Link>\r\n </Button>\r\n </CardContent>\r\n </Card>\r\n </div>\r\n </div>\r\n </Layout>\r\n );\r\n }\r\n\r\n // Success - Has orders\r\n return (\r\n <Layout>\r\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-8\">\r\n {/* Header */}\r\n <div className=\"flex items-center gap-4 mb-8\">\r\n <Button variant=\"ghost\" size=\"icon\" asChild>\r\n <Link to=\"/\">\r\n <ArrowLeft className=\"h-4 w-4\" />\r\n </Link>\r\n </Button>\r\n <div>\r\n <h1 className=\"text-3xl font-bold\">{t(\"title\", \"My Orders\")}</h1>\r\n <p className=\"text-muted-foreground\">\r\n {t(\"orderCount\", \"{{count}} order(s)\", { count: orders.length })}\r\n </p>\r\n </div>\r\n </div>\r\n\r\n {/* Orders List */}\r\n <div className=\"space-y-6\">\r\n {orders.map((order) => (\r\n <Card key={order.id} className=\"overflow-hidden\">\r\n {/* Order Header */}\r\n <div className=\"bg-muted/50 px-6 py-4 border-b\">\r\n <div className=\"flex flex-col md:flex-row md:items-center md:justify-between gap-4\">\r\n <div className=\"flex flex-wrap items-center gap-x-6 gap-y-2 text-sm\">\r\n <div>\r\n <span className=\"text-muted-foreground\">\r\n {t(\"orderNumber\", \"Order\")}:\r\n </span>{\" \"}\r\n <span className=\"font-mono font-medium\">\r\n #{order.id.slice(0, 8)}\r\n </span>\r\n </div>\r\n <div className=\"flex items-center gap-1.5 text-muted-foreground\">\r\n <Calendar className=\"w-4 h-4\" />\r\n <span>{formatDate(order.created_at)}</span>\r\n </div>\r\n <div className=\"flex items-center gap-1.5 text-muted-foreground\">\r\n <CreditCard className=\"w-4 h-4\" />\r\n <Badge\r\n variant={getPaymentStatusBadge(order.payment_status)}\r\n className=\"text-xs\"\r\n >\r\n {order.payment_status === \"paid\"\r\n ? t(\"paid\", \"Paid\")\r\n : t(\"unpaid\", \"Unpaid\")}\r\n </Badge>\r\n </div>\r\n </div>\r\n <div className=\"flex items-center gap-3\">\r\n <Badge\r\n variant={getStatusBadgeVariant(order.status)}\r\n className=\"flex items-center gap-1.5\"\r\n >\r\n {getStatusIcon(order.status)}\r\n <span className=\"capitalize\">{order.status}</span>\r\n </Badge>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Order Items */}\r\n <CardContent className=\"p-6\">\r\n <div className=\"space-y-4\">\r\n {order.product_data?.map((item, index) => (\r\n <div\r\n key={index}\r\n className=\"flex gap-4 pb-4 last:pb-0 last:border-0 border-b border-border/50\"\r\n >\r\n {/* Product Image */}\r\n <div className=\"flex-shrink-0\">\r\n <img\r\n src={item.img || \"/images/placeholder.png\"}\r\n alt={item.name}\r\n className=\"w-20 h-20 md:w-24 md:h-24 object-cover rounded-lg border\"\r\n onError={(e) => {\r\n (e.target as HTMLImageElement).src =\r\n \"/images/placeholder.png\";\r\n }}\r\n />\r\n </div>\r\n\r\n {/* Product Details */}\r\n <div className=\"flex-1 min-w-0\">\r\n <h3 className=\"font-semibold text-base md:text-lg truncate\">\r\n {item.name}\r\n </h3>\r\n {item.description && (\r\n <p className=\"text-sm text-muted-foreground line-clamp-2 mt-1\">\r\n {item.description}\r\n </p>\r\n )}\r\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1 mt-2 text-sm\">\r\n <span className=\"text-muted-foreground\">\r\n {t(\"quantity\", \"Qty\")}:{\" \"}\r\n <span className=\"font-medium text-foreground\">\r\n {item.quantity}\r\n </span>\r\n </span>\r\n <span className=\"font-semibold text-foreground\">\r\n {formatCurrency(item.amount, order.currency)}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n\r\n {/* Order Total */}\r\n <div className=\"flex items-center justify-between mt-6 pt-4 border-t\">\r\n <span className=\"text-muted-foreground\">\r\n {t(\"total\", \"Total\")}\r\n </span>\r\n <span className=\"text-xl font-bold\">\r\n {formatCurrency(order.total_amount, order.currency)}\r\n </span>\r\n </div>\r\n </CardContent>\r\n </Card>\r\n ))}\r\n </div>\r\n\r\n {/* Continue Shopping */}\r\n <div className=\"mt-8 text-center\">\r\n <Button variant=\"outline\" asChild>\r\n <Link to=\"/products\">\r\n <ShoppingBag className=\"w-4 h-4 mr-2\" />\r\n {t(\"continueShopping\", \"Continue Shopping\")}\r\n </Link>\r\n </Button>\r\n </div>\r\n </div>\r\n </Layout>\r\n );\r\n}\r\n\r\nexport default MyOrdersPage;\r\n"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"path": "my-orders-page/lang/en.json",
|
|
34
34
|
"type": "registry:lang",
|
|
35
35
|
"target": "$modules$/my-orders-page/lang/en.json",
|
|
36
|
-
"content": "{\n \"title\": \"My Orders\",\n \"loadError\": \"Failed to load orders. Please try again.\",\n \"loginRequired\": \"Login Required\",\n \"loginRequiredDescription\": \"Please login to view your orders.\",\n \"login\": \"Login\",\n \"createAccount\": \"Create Account\",\n \"loadingOrders\": \"Loading Orders\",\n \"pleaseWait\": \"Please wait...\",\n \"errorTitle\": \"Something went wrong\",\n \"errorDescription\": \"We couldn't load your orders. Please try again.\",\n \"tryAgain\": \"Try Again\",\n \"noOrders\": \"No Orders Yet\",\n \"noOrdersDescription\": \"You haven't placed any orders yet. Start shopping to see your orders here.\",\n \"startShopping\": \"Start Shopping\",\n \"orderCount\": \"{{count}} order(s)\",\n \"orderNumber\": \"Order\",\n \"paid\": \"Paid\",\n \"unpaid\": \"Unpaid\",\n \"quantity\": \"Qty\",\n \"total\": \"Total\",\n \"continueShopping\": \"Continue Shopping\"\n}\n"
|
|
36
|
+
"content": "{\r\n \"title\": \"My Orders\",\r\n \"loadError\": \"Failed to load orders. Please try again.\",\r\n \"loginRequired\": \"Login Required\",\r\n \"loginRequiredDescription\": \"Please login to view your orders.\",\r\n \"login\": \"Login\",\r\n \"createAccount\": \"Create Account\",\r\n \"loadingOrders\": \"Loading Orders\",\r\n \"pleaseWait\": \"Please wait...\",\r\n \"errorTitle\": \"Something went wrong\",\r\n \"errorDescription\": \"We couldn't load your orders. Please try again.\",\r\n \"tryAgain\": \"Try Again\",\r\n \"noOrders\": \"No Orders Yet\",\r\n \"noOrdersDescription\": \"You haven't placed any orders yet. Start shopping to see your orders here.\",\r\n \"startShopping\": \"Start Shopping\",\r\n \"orderCount\": \"{{count}} order(s)\",\r\n \"orderNumber\": \"Order\",\r\n \"paid\": \"Paid\",\r\n \"unpaid\": \"Unpaid\",\r\n \"quantity\": \"Qty\",\r\n \"total\": \"Total\",\r\n \"continueShopping\": \"Continue Shopping\"\r\n}\r\n"
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
"path": "my-orders-page/lang/tr.json",
|
|
40
40
|
"type": "registry:lang",
|
|
41
41
|
"target": "$modules$/my-orders-page/lang/tr.json",
|
|
42
|
-
"content": "{\n \"title\": \"Siparişlerim\",\n \"loadError\": \"Siparişler yüklenemedi. Lütfen tekrar deneyin.\",\n \"loginRequired\": \"Giriş Gerekli\",\n \"loginRequiredDescription\": \"Siparişlerinizi görmek için lütfen giriş yapın.\",\n \"login\": \"Giriş Yap\",\n \"createAccount\": \"Hesap Oluştur\",\n \"loadingOrders\": \"Siparişler Yükleniyor\",\n \"pleaseWait\": \"Lütfen bekleyin...\",\n \"errorTitle\": \"Bir şeyler ters gitti\",\n \"errorDescription\": \"Siparişlerinizi yükleyemedik. Lütfen tekrar deneyin.\",\n \"tryAgain\": \"Tekrar Dene\",\n \"noOrders\": \"Henüz Sipariş Yok\",\n \"noOrdersDescription\": \"Henüz hiç sipariş vermediniz. Siparişlerinizi burada görmek için alışverişe başlayın.\",\n \"startShopping\": \"Alışverişe Başla\",\n \"orderCount\": \"{{count}} sipariş\",\n \"orderNumber\": \"Sipariş\",\n \"paid\": \"Ödendi\",\n \"unpaid\": \"Ödenmedi\",\n \"quantity\": \"Adet\",\n \"total\": \"Toplam\",\n \"continueShopping\": \"Alışverişe Devam Et\"\n}\n"
|
|
42
|
+
"content": "{\r\n \"title\": \"Siparişlerim\",\r\n \"loadError\": \"Siparişler yüklenemedi. Lütfen tekrar deneyin.\",\r\n \"loginRequired\": \"Giriş Gerekli\",\r\n \"loginRequiredDescription\": \"Siparişlerinizi görmek için lütfen giriş yapın.\",\r\n \"login\": \"Giriş Yap\",\r\n \"createAccount\": \"Hesap Oluştur\",\r\n \"loadingOrders\": \"Siparişler Yükleniyor\",\r\n \"pleaseWait\": \"Lütfen bekleyin...\",\r\n \"errorTitle\": \"Bir şeyler ters gitti\",\r\n \"errorDescription\": \"Siparişlerinizi yükleyemedik. Lütfen tekrar deneyin.\",\r\n \"tryAgain\": \"Tekrar Dene\",\r\n \"noOrders\": \"Henüz Sipariş Yok\",\r\n \"noOrdersDescription\": \"Henüz hiç sipariş vermediniz. Siparişlerinizi burada görmek için alışverişe başlayın.\",\r\n \"startShopping\": \"Alışverişe Başla\",\r\n \"orderCount\": \"{{count}} sipariş\",\r\n \"orderNumber\": \"Sipariş\",\r\n \"paid\": \"Ödendi\",\r\n \"unpaid\": \"Ödenmedi\",\r\n \"quantity\": \"Adet\",\r\n \"total\": \"Toplam\",\r\n \"continueShopping\": \"Alışverişe Devam Et\"\r\n}\r\n"
|
|
43
43
|
}
|
|
44
44
|
],
|
|
45
45
|
"exports": {
|
|
@@ -14,25 +14,25 @@
|
|
|
14
14
|
"path": "newsletter-section/index.ts",
|
|
15
15
|
"type": "registry:index",
|
|
16
16
|
"target": "$modules$/newsletter-section/index.ts",
|
|
17
|
-
"content": "export * from './newsletter-section';\n"
|
|
17
|
+
"content": "export * from './newsletter-section';\r\n"
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"path": "newsletter-section/newsletter-section.tsx",
|
|
21
21
|
"type": "registry:component",
|
|
22
22
|
"target": "$modules$/newsletter-section/newsletter-section.tsx",
|
|
23
|
-
"content": "import { Button } from \"@/components/ui/button\";\nimport { Card, CardContent } from \"@/components/ui/card\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { useTranslation } from \"react-i18next\";\n\ninterface NewsletterSectionProps {\n image?: string;\n className?: string;\n}\n\nexport function NewsletterSection({\n image = \"/images/placeholder.png\",\n className,\n}: NewsletterSectionProps) {\n const { t } = useTranslation(\"newsletter-section\");\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n // Handle newsletter subscription\n };\n\n return (\n <section className={`px-4 py-20 bg-accent ${className || \"\"}`}>\n <div className=\"mx-auto max-w-6xl\">\n <Card className=\"overflow-hidden shadow-none p-0\">\n <CardContent className=\"p-0\">\n <div className=\"grid md:grid-cols-2 items-center\">\n <img\n loading=\"lazy\"\n decoding=\"async\"\n src={image}\n alt={t(\"imageAlt\", \"Newsletter\")}\n width={1200}\n height={800}\n className=\"h-64 w-full object-cover md:h-full\"\n />\n <form\n onSubmit={handleSubmit}\n className=\"flex flex-col gap-4 p-8 max-w-md w-full mx-auto\"\n >\n <div className=\"space-y-1 text-center\">\n <h2 className=\"text-2xl font-bold tracking-tight\">\n {t(\"title\", \"Get the inside scoop\")}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"description\", \"Join our newsletter to stay ahead.\")}\n </p>\n </div>\n <div className=\"grid gap-2 text-left\">\n <Label htmlFor=\"newsletter-email\">\n {t(\"emailLabel\", \"Email\")}\n </Label>\n <Input\n id=\"newsletter-email\"\n type=\"email\"\n placeholder={t(\"emailPlaceholder\", \"Enter your email\")}\n required\n />\n </div>\n <Button type=\"submit\">{t(\"subscribe\", \"Subscribe\")}</Button>\n </form>\n </div>\n </CardContent>\n </Card>\n </div>\n </section>\n );\n}\n"
|
|
23
|
+
"content": "import { Button } from \"@/components/ui/button\";\r\nimport { Card, CardContent } from \"@/components/ui/card\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Label } from \"@/components/ui/label\";\r\nimport { useTranslation } from \"react-i18next\";\r\n\r\ninterface NewsletterSectionProps {\r\n image?: string;\r\n className?: string;\r\n}\r\n\r\nexport function NewsletterSection({\r\n image = \"/images/placeholder.png\",\r\n className,\r\n}: NewsletterSectionProps) {\r\n const { t } = useTranslation(\"newsletter-section\");\r\n\r\n const handleSubmit = (e: React.FormEvent) => {\r\n e.preventDefault();\r\n // Handle newsletter subscription\r\n };\r\n\r\n return (\r\n <section className={`px-4 py-20 bg-accent ${className || \"\"}`}>\r\n <div className=\"mx-auto max-w-6xl\">\r\n <Card className=\"overflow-hidden shadow-none p-0\">\r\n <CardContent className=\"p-0\">\r\n <div className=\"grid md:grid-cols-2 items-center\">\r\n <img\r\n loading=\"lazy\"\r\n decoding=\"async\"\r\n src={image}\r\n alt={t(\"imageAlt\", \"Newsletter\")}\r\n width={1200}\r\n height={800}\r\n className=\"h-64 w-full object-cover md:h-full\"\r\n />\r\n <form\r\n onSubmit={handleSubmit}\r\n className=\"flex flex-col gap-4 p-8 max-w-md w-full mx-auto\"\r\n >\r\n <div className=\"space-y-1 text-center\">\r\n <h2 className=\"text-2xl font-bold tracking-tight\">\r\n {t(\"title\", \"Get the inside scoop\")}\r\n </h2>\r\n <p className=\"text-sm text-muted-foreground\">\r\n {t(\"description\", \"Join our newsletter to stay ahead.\")}\r\n </p>\r\n </div>\r\n <div className=\"grid gap-2 text-left\">\r\n <Label htmlFor=\"newsletter-email\">\r\n {t(\"emailLabel\", \"Email\")}\r\n </Label>\r\n <Input\r\n id=\"newsletter-email\"\r\n type=\"email\"\r\n placeholder={t(\"emailPlaceholder\", \"Enter your email\")}\r\n required\r\n />\r\n </div>\r\n <Button type=\"submit\">{t(\"subscribe\", \"Subscribe\")}</Button>\r\n </form>\r\n </div>\r\n </CardContent>\r\n </Card>\r\n </div>\r\n </section>\r\n );\r\n}\r\n"
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
"path": "newsletter-section/lang/en.json",
|
|
27
27
|
"type": "registry:lang",
|
|
28
28
|
"target": "$modules$/newsletter-section/lang/en.json",
|
|
29
|
-
"content": "{\n \"title\": \"Get the inside scoop\",\n \"description\": \"Join our newsletter to stay ahead.\",\n \"emailLabel\": \"Email\",\n \"emailPlaceholder\": \"Enter your email\",\n \"subscribe\": \"Subscribe\",\n \"imageAlt\": \"Newsletter\"\n}\n"
|
|
29
|
+
"content": "{\r\n \"title\": \"Get the inside scoop\",\r\n \"description\": \"Join our newsletter to stay ahead.\",\r\n \"emailLabel\": \"Email\",\r\n \"emailPlaceholder\": \"Enter your email\",\r\n \"subscribe\": \"Subscribe\",\r\n \"imageAlt\": \"Newsletter\"\r\n}\r\n"
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
"path": "newsletter-section/lang/tr.json",
|
|
33
33
|
"type": "registry:lang",
|
|
34
34
|
"target": "$modules$/newsletter-section/lang/tr.json",
|
|
35
|
-
"content": "{\n \"title\": \"Haberdar Olun\",\n \"description\": \"Bültenimize katılarak güncel kalın.\",\n \"emailLabel\": \"E-posta\",\n \"emailPlaceholder\": \"E-posta adresinizi girin\",\n \"subscribe\": \"Abone Ol\",\n \"imageAlt\": \"Bülten\"\n}\n"
|
|
35
|
+
"content": "{\r\n \"title\": \"Haberdar Olun\",\r\n \"description\": \"Bültenimize katılarak güncel kalın.\",\r\n \"emailLabel\": \"E-posta\",\r\n \"emailPlaceholder\": \"E-posta adresinizi girin\",\r\n \"subscribe\": \"Abone Ol\",\r\n \"imageAlt\": \"Bülten\"\r\n}\r\n"
|
|
36
36
|
}
|
|
37
37
|
],
|
|
38
38
|
"exports": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"path": "order-card-compact/index.ts",
|
|
13
13
|
"type": "registry:index",
|
|
14
14
|
"target": "$modules$/order-card-compact/index.ts",
|
|
15
|
-
"content": "export * from './order-card-compact';\n"
|
|
15
|
+
"content": "export * from './order-card-compact';\r\n"
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
"path": "order-card-compact/order-card-compact.tsx",
|
|
@@ -18,25 +18,25 @@
|
|
|
18
18
|
"path": "order-confirmation-page/index.ts",
|
|
19
19
|
"type": "registry:index",
|
|
20
20
|
"target": "$modules$/order-confirmation-page/index.ts",
|
|
21
|
-
"content": "export * from \"./order-confirmation-page\";\nexport { default } from \"./order-confirmation-page\";\n"
|
|
21
|
+
"content": "export * from \"./order-confirmation-page\";\r\nexport { default } from \"./order-confirmation-page\";\r\n"
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
"path": "order-confirmation-page/order-confirmation-page.tsx",
|
|
25
25
|
"type": "registry:page",
|
|
26
26
|
"target": "$modules$/order-confirmation-page/order-confirmation-page.tsx",
|
|
27
|
-
"content": "import { useEffect, useState } from \"react\";\nimport { Link, useParams, useSearchParams } from \"react-router\";\nimport {\n CheckCircle,\n Package,\n Truck,\n CreditCard,\n ArrowLeft,\n Clock,\n AlertCircle,\n Loader2,\n ShoppingBag,\n} from \"lucide-react\";\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Separator } from \"@/components/ui/separator\";\nimport { Layout } from \"@/components/Layout\";\nimport { usePageTitle } from \"@/hooks/use-page-title\";\nimport { useTranslation } from \"react-i18next\";\nimport { formatPrice } from \"@/modules/ecommerce-core\";\nimport { customerClient } from \"@/modules/api\";\nimport constants from \"@/constants/constants.json\";\n\ninterface CheckoutData {\n items: any[];\n total: number;\n customerInfo: {\n firstName: string;\n lastName: string;\n email: string;\n phone: string;\n address: string;\n city: string;\n postalCode: string;\n country: string;\n notes?: string;\n };\n paymentMethod: string;\n paymentProvider: string;\n}\n\nexport function OrderConfirmationPage() {\n const { t } = useTranslation(\"order-confirmation-page\");\n usePageTitle({ title: t(\"title\", \"Order Confirmation\") });\n\n const { orderId } = useParams<{ orderId: string }>();\n const [searchParams] = useSearchParams();\n const sessionId = searchParams.get(\"session_id\");\n\n const currency = (constants as any).site?.currency || \"USD\";\n\n const [checkoutData, setCheckoutData] = useState<CheckoutData | null>(null);\n const [paymentStatus, setPaymentStatus] = useState<string | null>(null);\n const [isCheckingStatus, setIsCheckingStatus] = useState(false);\n const [statusError, setStatusError] = useState<string | null>(null);\n\n // Check if this is a Stripe payment\n const isStripePayment = orderId?.startsWith(\"stripe-\") || !!sessionId;\n\n useEffect(() => {\n window.scrollTo(0, 0);\n\n // Load checkout data from localStorage\n const savedData = localStorage.getItem(\"pending_checkout\");\n if (savedData) {\n try {\n setCheckoutData(JSON.parse(savedData));\n // Clear after loading\n localStorage.removeItem(\"pending_checkout\");\n } catch (e) {\n console.error(\"Failed to parse checkout data:\", e);\n }\n }\n\n // If Stripe payment, check status\n if (isStripePayment && (sessionId || orderId)) {\n checkStripePaymentStatus();\n }\n }, []);\n\n const checkStripePaymentStatus = async () => {\n const sid = sessionId || orderId?.replace(\"stripe-\", \"\");\n if (!sid) return;\n\n setIsCheckingStatus(true);\n setStatusError(null);\n\n try {\n const response = await (customerClient as any).payment.status({ sessionId: sid });\n setPaymentStatus(response.status);\n } catch (error: any) {\n console.error(\"Payment status check error:\", error);\n setStatusError(error.message || \"An error occurred\");\n } finally {\n setIsCheckingStatus(false);\n }\n };\n\n // No checkout data found\n if (!checkoutData) {\n return (\n <Layout>\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-16\">\n <div className=\"max-w-md mx-auto text-center\">\n <Card>\n <CardContent className=\"pt-8 pb-8\">\n <Package className=\"w-16 h-16 text-muted-foreground mx-auto mb-4\" />\n <h1 className=\"text-2xl font-bold mb-2\">\n {t(\"orderNotFound\", \"Order Not Found\")}\n </h1>\n <p className=\"text-muted-foreground mb-6\">\n {t(\n \"orderNotFoundDescription\",\n \"We couldn't find the order details. Please check your email for confirmation.\"\n )}\n </p>\n <Button asChild>\n <Link to=\"/products\">\n <ShoppingBag className=\"w-4 h-4 mr-2\" />\n {t(\"continueShopping\", \"Continue Shopping\")}\n </Link>\n </Button>\n </CardContent>\n </Card>\n </div>\n </div>\n </Layout>\n );\n }\n\n const { items, total, customerInfo, paymentMethod, paymentProvider } = checkoutData;\n\n const getPaymentMethodDisplay = () => {\n if (paymentProvider === \"cash_on_delivery\" || paymentMethod === \"cash\") {\n return {\n icon: <Truck className=\"w-4 h-4 text-green-600\" />,\n label: t(\"cashOnDelivery\", \"Cash on Delivery\"),\n };\n }\n if (paymentProvider === \"bank_transfer\" || paymentMethod === \"transfer\") {\n return {\n icon: <CreditCard className=\"w-4 h-4 text-primary\" />,\n label: t(\"bankTransfer\", \"Bank Transfer\"),\n };\n }\n return {\n icon: <CreditCard className=\"w-4 h-4 text-blue-600\" />,\n label: t(\"creditCard\", \"Credit Card\"),\n };\n };\n\n const paymentDisplay = getPaymentMethodDisplay();\n\n return (\n <Layout>\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-8\">\n <div className=\"max-w-4xl mx-auto\">\n {/* Success Header */}\n <div className=\"text-center mb-8\">\n <div className=\"w-16 h-16 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mx-auto mb-4\">\n <CheckCircle className=\"w-8 h-8 text-green-600 dark:text-green-400\" />\n </div>\n <h1 className=\"text-3xl font-bold text-green-600 dark:text-green-400 mb-2\">\n {t(\"title\", \"Order Confirmed!\")}\n </h1>\n <p className=\"text-muted-foreground\">\n {t(\n \"thankYou\",\n \"Thank you for your order! We've received your order and will process it shortly.\"\n )}\n </p>\n </div>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-8\">\n {/* Order Details */}\n <div className=\"lg:col-span-2 space-y-6\">\n {/* Order Info */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Package className=\"w-5 h-5\" />\n {t(\"orderInformation\", \"Order Information\")}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {orderId && (\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"orderId\", \"Order ID\")}\n </p>\n <p className=\"font-semibold font-mono\">#{orderId.slice(0, 12)}</p>\n </div>\n )}\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"orderDate\", \"Order Date\")}\n </p>\n <p className=\"font-semibold\">\n {new Date().toLocaleDateString()}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"totalAmount\", \"Total Amount\")}\n </p>\n <p className=\"font-semibold text-lg\">\n {formatPrice(total, currency)}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"paymentMethod\", \"Payment Method\")}\n </p>\n <div className=\"flex items-center gap-2\">\n {paymentDisplay.icon}\n <span className=\"font-semibold\">{paymentDisplay.label}</span>\n </div>\n </div>\n {isStripePayment && (\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"paymentStatus\", \"Payment Status\")}\n </p>\n <div className=\"flex items-center gap-2\">\n {isCheckingStatus ? (\n <div className=\"flex items-center gap-2 text-muted-foreground\">\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n <span className=\"text-sm\">{t(\"checking\", \"Checking...\")}</span>\n </div>\n ) : statusError ? (\n <Badge variant=\"destructive\" className=\"flex items-center gap-1\">\n <AlertCircle className=\"w-3 h-3\" />\n {t(\"statusError\", \"Error\")}\n </Badge>\n ) : paymentStatus === \"succeeded\" ? (\n <Badge className=\"bg-green-100 text-green-800 border-green-200 flex items-center gap-1\">\n <CheckCircle className=\"w-3 h-3\" />\n {t(\"paymentSucceeded\", \"Paid\")}\n </Badge>\n ) : paymentStatus === \"processing\" ? (\n <Badge className=\"bg-blue-100 text-blue-800 border-blue-200 flex items-center gap-1\">\n <Loader2 className=\"w-3 h-3 animate-spin\" />\n {t(\"processing\", \"Processing\")}\n </Badge>\n ) : paymentStatus === \"requires_payment_method\" ? (\n <Badge className=\"bg-yellow-100 text-yellow-800 border-yellow-200 flex items-center gap-1\">\n <AlertCircle className=\"w-3 h-3\" />\n {t(\"requiresPayment\", \"Requires Payment\")}\n </Badge>\n ) : paymentStatus ? (\n <Badge variant=\"secondary\" className=\"flex items-center gap-1\">\n <Clock className=\"w-3 h-3\" />\n {paymentStatus}\n </Badge>\n ) : null}\n </div>\n </div>\n )}\n <div>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"orderStatus\", \"Order Status\")}\n </p>\n <Badge className=\"bg-yellow-100 text-yellow-800 border-yellow-200\">\n <Clock className=\"w-3 h-3 mr-1\" />\n {t(\"pending\", \"Pending\")}\n </Badge>\n </div>\n </div>\n </CardContent>\n </Card>\n\n {/* Delivery Info */}\n <Card>\n <CardHeader>\n <CardTitle>{t(\"deliveryInformation\", \"Delivery Information\")}</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-2\">\n <p className=\"font-semibold\">\n {customerInfo.firstName} {customerInfo.lastName}\n </p>\n <p className=\"text-sm text-muted-foreground\">{customerInfo.email}</p>\n <p className=\"text-sm text-muted-foreground\">{customerInfo.phone}</p>\n <div className=\"mt-3\">\n <p className=\"text-sm font-medium text-muted-foreground\">\n {t(\"address\", \"Address\")}:\n </p>\n <p className=\"text-sm\">{customerInfo.address}</p>\n <p className=\"text-sm\">\n {customerInfo.city} {customerInfo.postalCode}\n </p>\n </div>\n {customerInfo.notes && (\n <div className=\"mt-3\">\n <p className=\"text-sm font-medium text-muted-foreground\">\n {t(\"notes\", \"Notes\")}:\n </p>\n <p className=\"text-sm\">{customerInfo.notes}</p>\n </div>\n )}\n </div>\n </CardContent>\n </Card>\n\n {/* Order Items */}\n <Card>\n <CardHeader>\n <CardTitle>{t(\"orderItems\", \"Order Items\")}</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-4\">\n {items.map((item: any, index: number) => (\n <div key={item.id || index} className=\"flex gap-4\">\n <img\n src={item.product?.images?.[0] || \"/images/placeholder.png\"}\n alt={item.product?.name || \"Product\"}\n className=\"w-16 h-16 object-cover rounded border\"\n />\n <div className=\"flex-1\">\n <h4 className=\"font-medium\">{item.product?.name}</h4>\n <div className=\"flex justify-between items-center mt-2\">\n <span className=\"text-sm\">\n {t(\"qty\", \"Qty\")}: {item.quantity}\n </span>\n <span className=\"font-semibold\">\n {formatPrice(\n (item.product?.on_sale\n ? item.product?.sale_price\n : item.product?.price) * item.quantity,\n currency\n )}\n </span>\n </div>\n </div>\n </div>\n ))}\n </div>\n\n <Separator className=\"my-4\" />\n\n <div className=\"flex justify-between font-semibold text-lg\">\n <span>{t(\"total\", \"Total\")}</span>\n <span>{formatPrice(total, currency)}</span>\n </div>\n </CardContent>\n </Card>\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-6\">\n {/* Bank Transfer Instructions */}\n {(paymentProvider === \"bank_transfer\" || paymentMethod === \"transfer\") && (\n <Card>\n <CardHeader>\n <CardTitle className=\"text-lg\">\n {t(\"paymentInstructions\", \"Payment Instructions\")}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"p-4 bg-primary/10 border border-primary/20 rounded-lg\">\n <p className=\"text-sm font-medium text-primary mb-2\">\n {t(\"bankTransferDetails\", \"Bank Transfer Details\")}\n </p>\n <p className=\"text-sm text-muted-foreground\">\n {t(\n \"bankDetailsEmail\",\n \"Bank details will be sent via email. Please complete the transfer within 48 hours.\"\n )}\n </p>\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Cash on Delivery Info */}\n {(paymentProvider === \"cash_on_delivery\" || paymentMethod === \"cash\") && (\n <Card>\n <CardHeader>\n <CardTitle className=\"text-lg\">\n {t(\"deliveryPayment\", \"Payment on Delivery\")}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"p-4 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg\">\n <p className=\"text-sm font-medium text-green-800 dark:text-green-200 mb-2\">\n {t(\"cashOnDeliveryInfo\", \"Cash on Delivery\")}\n </p>\n <p className=\"text-sm text-green-700 dark:text-green-300\">\n {t(\n \"codInstructions\",\n \"Pay when your order arrives. Our delivery team will contact you before delivery.\"\n )}\n </p>\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Actions */}\n <Card>\n <CardContent className=\"pt-6 space-y-4\">\n <Button asChild className=\"w-full\">\n <Link to=\"/products\">\n <ShoppingBag className=\"w-4 h-4 mr-2\" />\n {t(\"continueShopping\", \"Continue Shopping\")}\n </Link>\n </Button>\n\n <Button variant=\"outline\" asChild className=\"w-full\">\n <Link to=\"/\">\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n {t(\"backToHome\", \"Back to Home\")}\n </Link>\n </Button>\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n </div>\n </Layout>\n );\n}\n\nexport default OrderConfirmationPage;\n"
|
|
27
|
+
"content": "import { useEffect, useState } from \"react\";\r\nimport { Link, useParams, useSearchParams } from \"react-router\";\r\nimport {\r\n CheckCircle,\r\n Package,\r\n Truck,\r\n CreditCard,\r\n ArrowLeft,\r\n Clock,\r\n AlertCircle,\r\n Loader2,\r\n ShoppingBag,\r\n} from \"lucide-react\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\r\nimport { Badge } from \"@/components/ui/badge\";\r\nimport { Separator } from \"@/components/ui/separator\";\r\nimport { Layout } from \"@/components/Layout\";\r\nimport { usePageTitle } from \"@/hooks/use-page-title\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { formatPrice } from \"@/modules/ecommerce-core\";\r\nimport { customerClient } from \"@/modules/api\";\r\nimport constants from \"@/constants/constants.json\";\r\n\r\ninterface CheckoutData {\r\n items: any[];\r\n total: number;\r\n customerInfo: {\r\n firstName: string;\r\n lastName: string;\r\n email: string;\r\n phone: string;\r\n address: string;\r\n city: string;\r\n postalCode: string;\r\n country: string;\r\n notes?: string;\r\n };\r\n paymentMethod: string;\r\n paymentProvider: string;\r\n}\r\n\r\nexport function OrderConfirmationPage() {\r\n const { t } = useTranslation(\"order-confirmation-page\");\r\n usePageTitle({ title: t(\"title\", \"Order Confirmation\") });\r\n\r\n const { orderId } = useParams<{ orderId: string }>();\r\n const [searchParams] = useSearchParams();\r\n const sessionId = searchParams.get(\"session_id\");\r\n\r\n const currency = (constants as any).site?.currency || \"USD\";\r\n\r\n const [checkoutData, setCheckoutData] = useState<CheckoutData | null>(null);\r\n const [paymentStatus, setPaymentStatus] = useState<string | null>(null);\r\n const [isCheckingStatus, setIsCheckingStatus] = useState(false);\r\n const [statusError, setStatusError] = useState<string | null>(null);\r\n\r\n // Check if this is a Stripe payment\r\n const isStripePayment = orderId?.startsWith(\"stripe-\") || !!sessionId;\r\n\r\n useEffect(() => {\r\n window.scrollTo(0, 0);\r\n\r\n // Load checkout data from localStorage\r\n const savedData = localStorage.getItem(\"pending_checkout\");\r\n if (savedData) {\r\n try {\r\n setCheckoutData(JSON.parse(savedData));\r\n // Clear after loading\r\n localStorage.removeItem(\"pending_checkout\");\r\n } catch (e) {\r\n console.error(\"Failed to parse checkout data:\", e);\r\n }\r\n }\r\n\r\n // If Stripe payment, check status\r\n if (isStripePayment && (sessionId || orderId)) {\r\n checkStripePaymentStatus();\r\n }\r\n }, []);\r\n\r\n const checkStripePaymentStatus = async () => {\r\n const sid = sessionId || orderId?.replace(\"stripe-\", \"\");\r\n if (!sid) return;\r\n\r\n setIsCheckingStatus(true);\r\n setStatusError(null);\r\n\r\n try {\r\n const response = await (customerClient as any).payment.status({ sessionId: sid });\r\n setPaymentStatus(response.status);\r\n } catch (error: any) {\r\n console.error(\"Payment status check error:\", error);\r\n setStatusError(error.message || \"An error occurred\");\r\n } finally {\r\n setIsCheckingStatus(false);\r\n }\r\n };\r\n\r\n // No checkout data found\r\n if (!checkoutData) {\r\n return (\r\n <Layout>\r\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-16\">\r\n <div className=\"max-w-md mx-auto text-center\">\r\n <Card>\r\n <CardContent className=\"pt-8 pb-8\">\r\n <Package className=\"w-16 h-16 text-muted-foreground mx-auto mb-4\" />\r\n <h1 className=\"text-2xl font-bold mb-2\">\r\n {t(\"orderNotFound\", \"Order Not Found\")}\r\n </h1>\r\n <p className=\"text-muted-foreground mb-6\">\r\n {t(\r\n \"orderNotFoundDescription\",\r\n \"We couldn't find the order details. Please check your email for confirmation.\"\r\n )}\r\n </p>\r\n <Button asChild>\r\n <Link to=\"/products\">\r\n <ShoppingBag className=\"w-4 h-4 mr-2\" />\r\n {t(\"continueShopping\", \"Continue Shopping\")}\r\n </Link>\r\n </Button>\r\n </CardContent>\r\n </Card>\r\n </div>\r\n </div>\r\n </Layout>\r\n );\r\n }\r\n\r\n const { items, total, customerInfo, paymentMethod, paymentProvider } = checkoutData;\r\n\r\n const getPaymentMethodDisplay = () => {\r\n if (paymentProvider === \"cash_on_delivery\" || paymentMethod === \"cash\") {\r\n return {\r\n icon: <Truck className=\"w-4 h-4 text-green-600\" />,\r\n label: t(\"cashOnDelivery\", \"Cash on Delivery\"),\r\n };\r\n }\r\n if (paymentProvider === \"bank_transfer\" || paymentMethod === \"transfer\") {\r\n return {\r\n icon: <CreditCard className=\"w-4 h-4 text-primary\" />,\r\n label: t(\"bankTransfer\", \"Bank Transfer\"),\r\n };\r\n }\r\n return {\r\n icon: <CreditCard className=\"w-4 h-4 text-blue-600\" />,\r\n label: t(\"creditCard\", \"Credit Card\"),\r\n };\r\n };\r\n\r\n const paymentDisplay = getPaymentMethodDisplay();\r\n\r\n return (\r\n <Layout>\r\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-8\">\r\n <div className=\"max-w-4xl mx-auto\">\r\n {/* Success Header */}\r\n <div className=\"text-center mb-8\">\r\n <div className=\"w-16 h-16 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mx-auto mb-4\">\r\n <CheckCircle className=\"w-8 h-8 text-green-600 dark:text-green-400\" />\r\n </div>\r\n <h1 className=\"text-3xl font-bold text-green-600 dark:text-green-400 mb-2\">\r\n {t(\"title\", \"Order Confirmed!\")}\r\n </h1>\r\n <p className=\"text-muted-foreground\">\r\n {t(\r\n \"thankYou\",\r\n \"Thank you for your order! We've received your order and will process it shortly.\"\r\n )}\r\n </p>\r\n </div>\r\n\r\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-8\">\r\n {/* Order Details */}\r\n <div className=\"lg:col-span-2 space-y-6\">\r\n {/* Order Info */}\r\n <Card>\r\n <CardHeader>\r\n <CardTitle className=\"flex items-center gap-2\">\r\n <Package className=\"w-5 h-5\" />\r\n {t(\"orderInformation\", \"Order Information\")}\r\n </CardTitle>\r\n </CardHeader>\r\n <CardContent className=\"space-y-4\">\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\r\n {orderId && (\r\n <div>\r\n <p className=\"text-sm text-muted-foreground\">\r\n {t(\"orderId\", \"Order ID\")}\r\n </p>\r\n <p className=\"font-semibold font-mono\">#{orderId.slice(0, 12)}</p>\r\n </div>\r\n )}\r\n <div>\r\n <p className=\"text-sm text-muted-foreground\">\r\n {t(\"orderDate\", \"Order Date\")}\r\n </p>\r\n <p className=\"font-semibold\">\r\n {new Date().toLocaleDateString()}\r\n </p>\r\n </div>\r\n <div>\r\n <p className=\"text-sm text-muted-foreground\">\r\n {t(\"totalAmount\", \"Total Amount\")}\r\n </p>\r\n <p className=\"font-semibold text-lg\">\r\n {formatPrice(total, currency)}\r\n </p>\r\n </div>\r\n <div>\r\n <p className=\"text-sm text-muted-foreground\">\r\n {t(\"paymentMethod\", \"Payment Method\")}\r\n </p>\r\n <div className=\"flex items-center gap-2\">\r\n {paymentDisplay.icon}\r\n <span className=\"font-semibold\">{paymentDisplay.label}</span>\r\n </div>\r\n </div>\r\n {isStripePayment && (\r\n <div>\r\n <p className=\"text-sm text-muted-foreground\">\r\n {t(\"paymentStatus\", \"Payment Status\")}\r\n </p>\r\n <div className=\"flex items-center gap-2\">\r\n {isCheckingStatus ? (\r\n <div className=\"flex items-center gap-2 text-muted-foreground\">\r\n <Loader2 className=\"w-4 h-4 animate-spin\" />\r\n <span className=\"text-sm\">{t(\"checking\", \"Checking...\")}</span>\r\n </div>\r\n ) : statusError ? (\r\n <Badge variant=\"destructive\" className=\"flex items-center gap-1\">\r\n <AlertCircle className=\"w-3 h-3\" />\r\n {t(\"statusError\", \"Error\")}\r\n </Badge>\r\n ) : paymentStatus === \"succeeded\" ? (\r\n <Badge className=\"bg-green-100 text-green-800 border-green-200 flex items-center gap-1\">\r\n <CheckCircle className=\"w-3 h-3\" />\r\n {t(\"paymentSucceeded\", \"Paid\")}\r\n </Badge>\r\n ) : paymentStatus === \"processing\" ? (\r\n <Badge className=\"bg-blue-100 text-blue-800 border-blue-200 flex items-center gap-1\">\r\n <Loader2 className=\"w-3 h-3 animate-spin\" />\r\n {t(\"processing\", \"Processing\")}\r\n </Badge>\r\n ) : paymentStatus === \"requires_payment_method\" ? (\r\n <Badge className=\"bg-yellow-100 text-yellow-800 border-yellow-200 flex items-center gap-1\">\r\n <AlertCircle className=\"w-3 h-3\" />\r\n {t(\"requiresPayment\", \"Requires Payment\")}\r\n </Badge>\r\n ) : paymentStatus ? (\r\n <Badge variant=\"secondary\" className=\"flex items-center gap-1\">\r\n <Clock className=\"w-3 h-3\" />\r\n {paymentStatus}\r\n </Badge>\r\n ) : null}\r\n </div>\r\n </div>\r\n )}\r\n <div>\r\n <p className=\"text-sm text-muted-foreground\">\r\n {t(\"orderStatus\", \"Order Status\")}\r\n </p>\r\n <Badge className=\"bg-yellow-100 text-yellow-800 border-yellow-200\">\r\n <Clock className=\"w-3 h-3 mr-1\" />\r\n {t(\"pending\", \"Pending\")}\r\n </Badge>\r\n </div>\r\n </div>\r\n </CardContent>\r\n </Card>\r\n\r\n {/* Delivery Info */}\r\n <Card>\r\n <CardHeader>\r\n <CardTitle>{t(\"deliveryInformation\", \"Delivery Information\")}</CardTitle>\r\n </CardHeader>\r\n <CardContent>\r\n <div className=\"space-y-2\">\r\n <p className=\"font-semibold\">\r\n {customerInfo.firstName} {customerInfo.lastName}\r\n </p>\r\n <p className=\"text-sm text-muted-foreground\">{customerInfo.email}</p>\r\n <p className=\"text-sm text-muted-foreground\">{customerInfo.phone}</p>\r\n <div className=\"mt-3\">\r\n <p className=\"text-sm font-medium text-muted-foreground\">\r\n {t(\"address\", \"Address\")}:\r\n </p>\r\n <p className=\"text-sm\">{customerInfo.address}</p>\r\n <p className=\"text-sm\">\r\n {customerInfo.city} {customerInfo.postalCode}\r\n </p>\r\n </div>\r\n {customerInfo.notes && (\r\n <div className=\"mt-3\">\r\n <p className=\"text-sm font-medium text-muted-foreground\">\r\n {t(\"notes\", \"Notes\")}:\r\n </p>\r\n <p className=\"text-sm\">{customerInfo.notes}</p>\r\n </div>\r\n )}\r\n </div>\r\n </CardContent>\r\n </Card>\r\n\r\n {/* Order Items */}\r\n <Card>\r\n <CardHeader>\r\n <CardTitle>{t(\"orderItems\", \"Order Items\")}</CardTitle>\r\n </CardHeader>\r\n <CardContent>\r\n <div className=\"space-y-4\">\r\n {items.map((item: any, index: number) => (\r\n <div key={item.id || index} className=\"flex gap-4\">\r\n <img\r\n src={item.product?.images?.[0] || \"/images/placeholder.png\"}\r\n alt={item.product?.name || \"Product\"}\r\n className=\"w-16 h-16 object-cover rounded border\"\r\n />\r\n <div className=\"flex-1\">\r\n <h4 className=\"font-medium\">{item.product?.name}</h4>\r\n <div className=\"flex justify-between items-center mt-2\">\r\n <span className=\"text-sm\">\r\n {t(\"qty\", \"Qty\")}: {item.quantity}\r\n </span>\r\n <span className=\"font-semibold\">\r\n {formatPrice(\r\n (item.product?.on_sale\r\n ? item.product?.sale_price\r\n : item.product?.price) * item.quantity,\r\n currency\r\n )}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n\r\n <Separator className=\"my-4\" />\r\n\r\n <div className=\"flex justify-between font-semibold text-lg\">\r\n <span>{t(\"total\", \"Total\")}</span>\r\n <span>{formatPrice(total, currency)}</span>\r\n </div>\r\n </CardContent>\r\n </Card>\r\n </div>\r\n\r\n {/* Sidebar */}\r\n <div className=\"space-y-6\">\r\n {/* Bank Transfer Instructions */}\r\n {(paymentProvider === \"bank_transfer\" || paymentMethod === \"transfer\") && (\r\n <Card>\r\n <CardHeader>\r\n <CardTitle className=\"text-lg\">\r\n {t(\"paymentInstructions\", \"Payment Instructions\")}\r\n </CardTitle>\r\n </CardHeader>\r\n <CardContent>\r\n <div className=\"p-4 bg-primary/10 border border-primary/20 rounded-lg\">\r\n <p className=\"text-sm font-medium text-primary mb-2\">\r\n {t(\"bankTransferDetails\", \"Bank Transfer Details\")}\r\n </p>\r\n <p className=\"text-sm text-muted-foreground\">\r\n {t(\r\n \"bankDetailsEmail\",\r\n \"Bank details will be sent via email. Please complete the transfer within 48 hours.\"\r\n )}\r\n </p>\r\n </div>\r\n </CardContent>\r\n </Card>\r\n )}\r\n\r\n {/* Cash on Delivery Info */}\r\n {(paymentProvider === \"cash_on_delivery\" || paymentMethod === \"cash\") && (\r\n <Card>\r\n <CardHeader>\r\n <CardTitle className=\"text-lg\">\r\n {t(\"deliveryPayment\", \"Payment on Delivery\")}\r\n </CardTitle>\r\n </CardHeader>\r\n <CardContent>\r\n <div className=\"p-4 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg\">\r\n <p className=\"text-sm font-medium text-green-800 dark:text-green-200 mb-2\">\r\n {t(\"cashOnDeliveryInfo\", \"Cash on Delivery\")}\r\n </p>\r\n <p className=\"text-sm text-green-700 dark:text-green-300\">\r\n {t(\r\n \"codInstructions\",\r\n \"Pay when your order arrives. Our delivery team will contact you before delivery.\"\r\n )}\r\n </p>\r\n </div>\r\n </CardContent>\r\n </Card>\r\n )}\r\n\r\n {/* Actions */}\r\n <Card>\r\n <CardContent className=\"pt-6 space-y-4\">\r\n <Button asChild className=\"w-full\">\r\n <Link to=\"/products\">\r\n <ShoppingBag className=\"w-4 h-4 mr-2\" />\r\n {t(\"continueShopping\", \"Continue Shopping\")}\r\n </Link>\r\n </Button>\r\n\r\n <Button variant=\"outline\" asChild className=\"w-full\">\r\n <Link to=\"/\">\r\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\r\n {t(\"backToHome\", \"Back to Home\")}\r\n </Link>\r\n </Button>\r\n </CardContent>\r\n </Card>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </Layout>\r\n );\r\n}\r\n\r\nexport default OrderConfirmationPage;\r\n"
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
"path": "order-confirmation-page/lang/en.json",
|
|
31
31
|
"type": "registry:lang",
|
|
32
32
|
"target": "$modules$/order-confirmation-page/lang/en.json",
|
|
33
|
-
"content": "{\n \"title\": \"Order Confirmed!\",\n \"orderNotFound\": \"Order Not Found\",\n \"orderNotFoundDescription\": \"We couldn't find the order details. Please check your email for confirmation.\",\n \"continueShopping\": \"Continue Shopping\",\n \"cashOnDelivery\": \"Cash on Delivery\",\n \"bankTransfer\": \"Bank Transfer\",\n \"creditCard\": \"Credit Card\",\n \"thankYou\": \"Thank you for your order! We've received your order and will process it shortly.\",\n \"orderInformation\": \"Order Information\",\n \"orderId\": \"Order ID\",\n \"orderDate\": \"Order Date\",\n \"totalAmount\": \"Total Amount\",\n \"paymentMethod\": \"Payment Method\",\n \"paymentStatus\": \"Payment Status\",\n \"checking\": \"Checking...\",\n \"statusError\": \"Error\",\n \"paymentSucceeded\": \"Paid\",\n \"processing\": \"Processing\",\n \"requiresPayment\": \"Requires Payment\",\n \"orderStatus\": \"Order Status\",\n \"pending\": \"Pending\",\n \"deliveryInformation\": \"Delivery Information\",\n \"address\": \"Address\",\n \"notes\": \"Notes\",\n \"orderItems\": \"Order Items\",\n \"qty\": \"Qty\",\n \"total\": \"Total\",\n \"paymentInstructions\": \"Payment Instructions\",\n \"bankTransferDetails\": \"Bank Transfer Details\",\n \"bankDetailsEmail\": \"Bank details will be sent via email. Please complete the transfer within 48 hours.\",\n \"deliveryPayment\": \"Payment on Delivery\",\n \"cashOnDeliveryInfo\": \"Cash on Delivery\",\n \"codInstructions\": \"Pay when your order arrives. Our delivery team will contact you before delivery.\",\n \"backToHome\": \"Back to Home\"\n}\n"
|
|
33
|
+
"content": "{\r\n \"title\": \"Order Confirmed!\",\r\n \"orderNotFound\": \"Order Not Found\",\r\n \"orderNotFoundDescription\": \"We couldn't find the order details. Please check your email for confirmation.\",\r\n \"continueShopping\": \"Continue Shopping\",\r\n \"cashOnDelivery\": \"Cash on Delivery\",\r\n \"bankTransfer\": \"Bank Transfer\",\r\n \"creditCard\": \"Credit Card\",\r\n \"thankYou\": \"Thank you for your order! We've received your order and will process it shortly.\",\r\n \"orderInformation\": \"Order Information\",\r\n \"orderId\": \"Order ID\",\r\n \"orderDate\": \"Order Date\",\r\n \"totalAmount\": \"Total Amount\",\r\n \"paymentMethod\": \"Payment Method\",\r\n \"paymentStatus\": \"Payment Status\",\r\n \"checking\": \"Checking...\",\r\n \"statusError\": \"Error\",\r\n \"paymentSucceeded\": \"Paid\",\r\n \"processing\": \"Processing\",\r\n \"requiresPayment\": \"Requires Payment\",\r\n \"orderStatus\": \"Order Status\",\r\n \"pending\": \"Pending\",\r\n \"deliveryInformation\": \"Delivery Information\",\r\n \"address\": \"Address\",\r\n \"notes\": \"Notes\",\r\n \"orderItems\": \"Order Items\",\r\n \"qty\": \"Qty\",\r\n \"total\": \"Total\",\r\n \"paymentInstructions\": \"Payment Instructions\",\r\n \"bankTransferDetails\": \"Bank Transfer Details\",\r\n \"bankDetailsEmail\": \"Bank details will be sent via email. Please complete the transfer within 48 hours.\",\r\n \"deliveryPayment\": \"Payment on Delivery\",\r\n \"cashOnDeliveryInfo\": \"Cash on Delivery\",\r\n \"codInstructions\": \"Pay when your order arrives. Our delivery team will contact you before delivery.\",\r\n \"backToHome\": \"Back to Home\"\r\n}\r\n"
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
"path": "order-confirmation-page/lang/tr.json",
|
|
37
37
|
"type": "registry:lang",
|
|
38
38
|
"target": "$modules$/order-confirmation-page/lang/tr.json",
|
|
39
|
-
"content": "{\n \"title\": \"Sipariş Onaylandı!\",\n \"orderNotFound\": \"Sipariş Bulunamadı\",\n \"orderNotFoundDescription\": \"Sipariş detaylarını bulamadık. Lütfen onay için e-postanızı kontrol edin.\",\n \"continueShopping\": \"Alışverişe Devam Et\",\n \"cashOnDelivery\": \"Kapıda Ödeme\",\n \"bankTransfer\": \"Havale/EFT\",\n \"creditCard\": \"Kredi Kartı\",\n \"thankYou\": \"Siparişiniz için teşekkürler! Siparişinizi aldık ve en kısa sürede işleme alacağız.\",\n \"orderInformation\": \"Sipariş Bilgileri\",\n \"orderId\": \"Sipariş No\",\n \"orderDate\": \"Sipariş Tarihi\",\n \"totalAmount\": \"Toplam Tutar\",\n \"paymentMethod\": \"Ödeme Yöntemi\",\n \"paymentStatus\": \"Ödeme Durumu\",\n \"checking\": \"Kontrol ediliyor...\",\n \"statusError\": \"Hata\",\n \"paymentSucceeded\": \"Ödendi\",\n \"processing\": \"İşleniyor\",\n \"requiresPayment\": \"Ödeme Gerekli\",\n \"orderStatus\": \"Sipariş Durumu\",\n \"pending\": \"Beklemede\",\n \"deliveryInformation\": \"Teslimat Bilgileri\",\n \"address\": \"Adres\",\n \"notes\": \"Notlar\",\n \"orderItems\": \"Sipariş Ürünleri\",\n \"qty\": \"Adet\",\n \"total\": \"Toplam\",\n \"paymentInstructions\": \"Ödeme Talimatları\",\n \"bankTransferDetails\": \"Havale/EFT Bilgileri\",\n \"bankDetailsEmail\": \"Banka bilgileri e-posta ile gönderilecektir. Lütfen transferi 48 saat içinde tamamlayın.\",\n \"deliveryPayment\": \"Teslimatta Ödeme\",\n \"cashOnDeliveryInfo\": \"Kapıda Ödeme\",\n \"codInstructions\": \"Siparişiniz geldiğinde ödeme yapın. Teslimat ekibimiz teslimat öncesi sizinle iletişime geçecektir.\",\n \"backToHome\": \"Ana Sayfaya Dön\"\n}\n"
|
|
39
|
+
"content": "{\r\n \"title\": \"Sipariş Onaylandı!\",\r\n \"orderNotFound\": \"Sipariş Bulunamadı\",\r\n \"orderNotFoundDescription\": \"Sipariş detaylarını bulamadık. Lütfen onay için e-postanızı kontrol edin.\",\r\n \"continueShopping\": \"Alışverişe Devam Et\",\r\n \"cashOnDelivery\": \"Kapıda Ödeme\",\r\n \"bankTransfer\": \"Havale/EFT\",\r\n \"creditCard\": \"Kredi Kartı\",\r\n \"thankYou\": \"Siparişiniz için teşekkürler! Siparişinizi aldık ve en kısa sürede işleme alacağız.\",\r\n \"orderInformation\": \"Sipariş Bilgileri\",\r\n \"orderId\": \"Sipariş No\",\r\n \"orderDate\": \"Sipariş Tarihi\",\r\n \"totalAmount\": \"Toplam Tutar\",\r\n \"paymentMethod\": \"Ödeme Yöntemi\",\r\n \"paymentStatus\": \"Ödeme Durumu\",\r\n \"checking\": \"Kontrol ediliyor...\",\r\n \"statusError\": \"Hata\",\r\n \"paymentSucceeded\": \"Ödendi\",\r\n \"processing\": \"İşleniyor\",\r\n \"requiresPayment\": \"Ödeme Gerekli\",\r\n \"orderStatus\": \"Sipariş Durumu\",\r\n \"pending\": \"Beklemede\",\r\n \"deliveryInformation\": \"Teslimat Bilgileri\",\r\n \"address\": \"Adres\",\r\n \"notes\": \"Notlar\",\r\n \"orderItems\": \"Sipariş Ürünleri\",\r\n \"qty\": \"Adet\",\r\n \"total\": \"Toplam\",\r\n \"paymentInstructions\": \"Ödeme Talimatları\",\r\n \"bankTransferDetails\": \"Havale/EFT Bilgileri\",\r\n \"bankDetailsEmail\": \"Banka bilgileri e-posta ile gönderilecektir. Lütfen transferi 48 saat içinde tamamlayın.\",\r\n \"deliveryPayment\": \"Teslimatta Ödeme\",\r\n \"cashOnDeliveryInfo\": \"Kapıda Ödeme\",\r\n \"codInstructions\": \"Siparişiniz geldiğinde ödeme yapın. Teslimat ekibimiz teslimat öncesi sizinle iletişime geçecektir.\",\r\n \"backToHome\": \"Ana Sayfaya Dön\"\r\n}\r\n"
|
|
40
40
|
}
|
|
41
41
|
],
|
|
42
42
|
"exports": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"path": "order-detail-block/index.ts",
|
|
13
13
|
"type": "registry:index",
|
|
14
14
|
"target": "$modules$/order-detail-block/index.ts",
|
|
15
|
-
"content": "export * from './order-detail-block';\n"
|
|
15
|
+
"content": "export * from './order-detail-block';\r\n"
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
"path": "order-detail-block/order-detail-block.tsx",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"path": "orders-list-block/index.ts",
|
|
14
14
|
"type": "registry:index",
|
|
15
15
|
"target": "$modules$/orders-list-block/index.ts",
|
|
16
|
-
"content": "export * from './orders-list-block';\n"
|
|
16
|
+
"content": "export * from './orders-list-block';\r\n"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"path": "orders-list-block/orders-list-block.tsx",
|