@promakeai/cli 0.3.2 → 0.3.3

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.
Files changed (113) hide show
  1. package/dist/index.js +415 -209
  2. package/dist/registry/about-page.json +3 -3
  3. package/dist/registry/about-section.json +4 -4
  4. package/dist/registry/animations.json +2 -2
  5. package/dist/registry/announcement-bar.json +4 -4
  6. package/dist/registry/api.json +1 -1
  7. package/dist/registry/auth-core.json +3 -3
  8. package/dist/registry/auth.json +70 -0
  9. package/dist/registry/bento-grid-section.json +4 -4
  10. package/dist/registry/blog-core.json +5 -5
  11. package/dist/registry/blog-list-page.json +3 -3
  12. package/dist/registry/blog-section.json +4 -4
  13. package/dist/registry/cards-carousel-section.json +4 -4
  14. package/dist/registry/cart-drawer.json +3 -3
  15. package/dist/registry/cart-page.json +3 -3
  16. package/dist/registry/case-study-page.json +3 -3
  17. package/dist/registry/category-section.json +3 -3
  18. package/dist/registry/checkout-page.json +3 -3
  19. package/dist/registry/coming-soon-page-minimal.json +4 -4
  20. package/dist/registry/coming-soon-page.json +4 -4
  21. package/dist/registry/contact-info-grid.json +4 -4
  22. package/dist/registry/contact-page-centered.json +4 -4
  23. package/dist/registry/contact-page-split.json +4 -4
  24. package/dist/registry/contact-page.json +3 -3
  25. package/dist/registry/content-section.json +4 -4
  26. package/dist/registry/cookie-consent.json +4 -4
  27. package/dist/registry/cookies-page.json +3 -3
  28. package/dist/registry/cta-section.json +3 -3
  29. package/dist/registry/docs/reset-password-page.md +36 -0
  30. package/dist/registry/ecommerce-core.json +10 -10
  31. package/dist/registry/empty-page.json +3 -3
  32. package/dist/registry/faq-categorized.json +4 -4
  33. package/dist/registry/faq-simple.json +4 -4
  34. package/dist/registry/favorites-blog-block.json +1 -1
  35. package/dist/registry/favorites-blog-page.json +4 -4
  36. package/dist/registry/favorites-ecommerce-block.json +1 -1
  37. package/dist/registry/favorites-ecommerce-page.json +4 -4
  38. package/dist/registry/feature-section.json +3 -3
  39. package/dist/registry/featured-products.json +3 -3
  40. package/dist/registry/footer-detailed.json +4 -4
  41. package/dist/registry/footer-minimal.json +3 -3
  42. package/dist/registry/footer.json +3 -3
  43. package/dist/registry/forgot-password-page-split.json +4 -4
  44. package/dist/registry/forgot-password-page.json +4 -4
  45. package/dist/registry/google-adsense.json +4 -4
  46. package/dist/registry/google-map.json +2 -2
  47. package/dist/registry/header-centered-pill.json +4 -4
  48. package/dist/registry/header-ecommerce.json +3 -3
  49. package/dist/registry/header-mega.json +4 -4
  50. package/dist/registry/header-minimal.json +4 -4
  51. package/dist/registry/header-simple.json +3 -3
  52. package/dist/registry/hero-carousel.json +3 -3
  53. package/dist/registry/hero-cta.json +4 -4
  54. package/dist/registry/hero-gradient.json +4 -4
  55. package/dist/registry/hero-grid.json +4 -4
  56. package/dist/registry/hero-profile.json +3 -3
  57. package/dist/registry/hero.json +3 -3
  58. package/dist/registry/landing-page-app.json +3 -3
  59. package/dist/registry/landing-page-saas.json +3 -3
  60. package/dist/registry/login-page-split.json +4 -4
  61. package/dist/registry/login-page.json +4 -4
  62. package/dist/registry/logo-cloud.json +4 -4
  63. package/dist/registry/masonry-grid.json +3 -3
  64. package/dist/registry/my-orders-page.json +4 -4
  65. package/dist/registry/newsletter-section.json +4 -4
  66. package/dist/registry/order-card-compact.json +1 -1
  67. package/dist/registry/order-confirmation-page.json +4 -4
  68. package/dist/registry/order-detail-block.json +1 -1
  69. package/dist/registry/orders-list-block.json +1 -1
  70. package/dist/registry/payment-success-block.json +1 -1
  71. package/dist/registry/portfolio-page.json +4 -4
  72. package/dist/registry/post-card.json +3 -3
  73. package/dist/registry/post-detail-block.json +1 -1
  74. package/dist/registry/post-detail-page.json +4 -4
  75. package/dist/registry/pricing-card.json +3 -3
  76. package/dist/registry/pricing-page.json +4 -4
  77. package/dist/registry/pricing-section.json +4 -4
  78. package/dist/registry/privacy-page.json +3 -3
  79. package/dist/registry/product-card-detailed.json +4 -4
  80. package/dist/registry/product-card-hover.json +4 -4
  81. package/dist/registry/product-card.json +3 -3
  82. package/dist/registry/product-detail-block.json +1 -1
  83. package/dist/registry/product-detail-page.json +4 -4
  84. package/dist/registry/product-detail-section.json +4 -4
  85. package/dist/registry/product-quick-view.json +4 -4
  86. package/dist/registry/products-page.json +3 -3
  87. package/dist/registry/reading-progress.json +4 -4
  88. package/dist/registry/register-page-split.json +4 -4
  89. package/dist/registry/register-page.json +4 -4
  90. package/dist/registry/related-posts-block.json +1 -1
  91. package/dist/registry/related-products-block.json +1 -1
  92. package/dist/registry/reset-password-page-split.json +4 -4
  93. package/dist/registry/reset-password-page.json +39 -0
  94. package/dist/registry/service-card.json +1 -1
  95. package/dist/registry/share-buttons.json +4 -4
  96. package/dist/registry/skill-card.json +1 -1
  97. package/dist/registry/team-page.json +4 -4
  98. package/dist/registry/terms-page.json +3 -3
  99. package/dist/registry/testimonials-carousel.json +4 -4
  100. package/dist/registry/testimonials-grid.json +4 -4
  101. package/dist/registry/timeline-section.json +4 -4
  102. package/dist/registry/video-hero.json +4 -4
  103. package/dist/registry/youtube-embed.json +4 -4
  104. package/package.json +2 -2
  105. package/template/.env +6 -6
  106. package/template/public/_redirects +1 -1
  107. package/template/public/robots.txt +14 -14
  108. package/template/src/components/GoogleAnalytics.tsx +34 -34
  109. package/template/src/components/LanguageSwitcher.tsx +53 -53
  110. package/template/src/components/ScriptInjector.tsx +62 -62
  111. package/template/src/lib/env.ts +19 -19
  112. package/template/src/router.tsx +14 -14
  113. package/template/src/vite-env.d.ts +1 -1
@@ -17,25 +17,25 @@
17
17
  "path": "product-detail-page/index.ts",
18
18
  "type": "registry:index",
19
19
  "target": "$modules$/product-detail-page/index.ts",
20
- "content": "export * from './product-detail-page';\nexport { ProductDetailPage as default } from './product-detail-page';\n"
20
+ "content": "export * from './product-detail-page';\r\nexport { ProductDetailPage as default } from './product-detail-page';\r\n"
21
21
  },
22
22
  {
23
23
  "path": "product-detail-page/product-detail-page.tsx",
24
24
  "type": "registry:page",
25
25
  "target": "$modules$/product-detail-page/product-detail-page.tsx",
26
- "content": "import { useParams } from \"react-router\";\nimport { useProductBySlug } from \"@/modules/ecommerce-core\";\nimport { ProductDetailBlock } from \"@/modules/product-detail-block\";\nimport { Layout } from \"@/components/Layout\";\nimport { usePageTitle } from \"@/hooks/use-page-title\";\nimport { useTranslation } from \"react-i18next\";\n\nexport function ProductDetailPage() {\n const { t } = useTranslation(\"product-detail-page\");\n const { slug } = useParams<{ slug: string }>();\n const { product, loading, error } = useProductBySlug(slug || \"\");\n\n usePageTitle({ title: product?.name || t(\"loading\", \"Loading...\") });\n\n if (loading) {\n return (\n <Layout>\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-8\">\n <div className=\"animate-pulse\">\n <div className=\"grid lg:grid-cols-2 gap-12\">\n <div className=\"aspect-square bg-muted rounded-lg\"></div>\n <div className=\"space-y-4\">\n <div className=\"h-6 bg-muted rounded w-1/4\"></div>\n <div className=\"h-10 bg-muted rounded w-3/4\"></div>\n <div className=\"h-4 bg-muted rounded w-1/3\"></div>\n <div className=\"h-8 bg-muted rounded w-1/4\"></div>\n <div className=\"space-y-2\">\n <div className=\"h-4 bg-muted rounded\"></div>\n <div className=\"h-4 bg-muted rounded\"></div>\n <div className=\"h-4 bg-muted rounded w-2/3\"></div>\n </div>\n <div className=\"h-12 bg-muted rounded w-1/2\"></div>\n </div>\n </div>\n </div>\n </div>\n </Layout>\n );\n }\n\n if (error || !product) {\n return (\n <Layout>\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-8 text-center\">\n <h1 className=\"text-2xl font-bold mb-4\">{t(\"notFound\", \"Product Not Found\")}</h1>\n <p className=\"text-muted-foreground\">{t(\"notFoundDescription\", \"The product you're looking for doesn't exist or has been removed.\")}</p>\n </div>\n </Layout>\n );\n }\n\n return (\n <Layout>\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-8\">\n <ProductDetailBlock product={product} />\n </div>\n </Layout>\n );\n}\n\nexport default ProductDetailPage;\n"
26
+ "content": "import { useParams } from \"react-router\";\r\nimport { useProductBySlug } from \"@/modules/ecommerce-core\";\r\nimport { ProductDetailBlock } from \"@/modules/product-detail-block\";\r\nimport { Layout } from \"@/components/Layout\";\r\nimport { usePageTitle } from \"@/hooks/use-page-title\";\r\nimport { useTranslation } from \"react-i18next\";\r\n\r\nexport function ProductDetailPage() {\r\n const { t } = useTranslation(\"product-detail-page\");\r\n const { slug } = useParams<{ slug: string }>();\r\n const { product, loading, error } = useProductBySlug(slug || \"\");\r\n\r\n usePageTitle({ title: product?.name || t(\"loading\", \"Loading...\") });\r\n\r\n if (loading) {\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=\"animate-pulse\">\r\n <div className=\"grid lg:grid-cols-2 gap-12\">\r\n <div className=\"aspect-square bg-muted rounded-lg\"></div>\r\n <div className=\"space-y-4\">\r\n <div className=\"h-6 bg-muted rounded w-1/4\"></div>\r\n <div className=\"h-10 bg-muted rounded w-3/4\"></div>\r\n <div className=\"h-4 bg-muted rounded w-1/3\"></div>\r\n <div className=\"h-8 bg-muted rounded w-1/4\"></div>\r\n <div className=\"space-y-2\">\r\n <div className=\"h-4 bg-muted rounded\"></div>\r\n <div className=\"h-4 bg-muted rounded\"></div>\r\n <div className=\"h-4 bg-muted rounded w-2/3\"></div>\r\n </div>\r\n <div className=\"h-12 bg-muted rounded w-1/2\"></div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </Layout>\r\n );\r\n }\r\n\r\n if (error || !product) {\r\n return (\r\n <Layout>\r\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 py-8 text-center\">\r\n <h1 className=\"text-2xl font-bold mb-4\">{t(\"notFound\", \"Product Not Found\")}</h1>\r\n <p className=\"text-muted-foreground\">{t(\"notFoundDescription\", \"The product you're looking for doesn't exist or has been removed.\")}</p>\r\n </div>\r\n </Layout>\r\n );\r\n }\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 <ProductDetailBlock product={product} />\r\n </div>\r\n </Layout>\r\n );\r\n}\r\n\r\nexport default ProductDetailPage;\r\n"
27
27
  },
28
28
  {
29
29
  "path": "product-detail-page/lang/en.json",
30
30
  "type": "registry:lang",
31
31
  "target": "$modules$/product-detail-page/lang/en.json",
32
- "content": "{\n \"loading\": \"Loading...\",\n \"notFound\": \"Product Not Found\",\n \"notFoundDescription\": \"The product you're looking for doesn't exist or has been removed.\"\n}\n"
32
+ "content": "{\r\n \"loading\": \"Loading...\",\r\n \"notFound\": \"Product Not Found\",\r\n \"notFoundDescription\": \"The product you're looking for doesn't exist or has been removed.\"\r\n}\r\n"
33
33
  },
34
34
  {
35
35
  "path": "product-detail-page/lang/tr.json",
36
36
  "type": "registry:lang",
37
37
  "target": "$modules$/product-detail-page/lang/tr.json",
38
- "content": "{\n \"loading\": \"Yükleniyor...\",\n \"notFound\": \"Ürün Bulunamadı\",\n \"notFoundDescription\": \"Aradığınız ürün mevcut değil veya kaldırılmış.\"\n}\n"
38
+ "content": "{\r\n \"loading\": \"Yükleniyor...\",\r\n \"notFound\": \"Ürün Bulunamadı\",\r\n \"notFoundDescription\": \"Aradığınız ürün mevcut değil veya kaldırılmış.\"\r\n}\r\n"
39
39
  }
40
40
  ],
41
41
  "exports": {
@@ -17,25 +17,25 @@
17
17
  "path": "product-detail-section/index.ts",
18
18
  "type": "registry:index",
19
19
  "target": "$modules$/product-detail-section/index.ts",
20
- "content": "export * from './product-detail-section';\n"
20
+ "content": "export * from './product-detail-section';\r\n"
21
21
  },
22
22
  {
23
23
  "path": "product-detail-section/product-detail-section.tsx",
24
24
  "type": "registry:component",
25
25
  "target": "$modules$/product-detail-section/product-detail-section.tsx",
26
- "content": "import { Star, Heart, Facebook, Twitter, MessageCircle } from \"lucide-react\";\nimport { toast } from \"sonner\";\nimport { Button } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\nimport { useTranslation } from \"react-i18next\";\nimport {\n useCart,\n useFavorites,\n formatPrice,\n type Product,\n} from \"@/modules/ecommerce-core\";\nimport constants from \"@/constants/constants.json\";\n\ninterface ProductDetailSectionProps {\n product: Product;\n className?: string;\n}\n\nexport function ProductDetailSection({\n product,\n className,\n}: ProductDetailSectionProps) {\n const { t } = useTranslation(\"product-detail-section\");\n const { addItem } = useCart();\n const { isFavorite, addToFavorites, removeFromFavorites } = useFavorites();\n const currency = (constants.site as any).currency || \"USD\";\n\n if (!product) {\n return null;\n }\n\n const price = product.on_sale && product.sale_price\n ? product.sale_price\n : product.price;\n\n const handleAddToCart = () => {\n addItem(product);\n toast.success(t(\"addedToCart\", \"Added to cart!\"));\n };\n\n const handleToggleFavorite = () => {\n if (isFavorite(product.id)) {\n removeFromFavorites(product.id);\n } else {\n addToFavorites(product);\n }\n };\n\n const renderStars = (rating: number) => {\n return Array.from({ length: 5 }, (_, i) => (\n <Star\n key={i}\n className={cn(\n \"w-4 h-4\",\n i < Math.floor(rating) ? \"fill-primary text-primary\" : \"text-primary\"\n )}\n />\n ));\n };\n\n return (\n <section className={cn(\"py-24\", className)}>\n <div className=\"container px-5 mx-auto\">\n <div className=\"lg:w-4/5 mx-auto flex flex-wrap\">\n <img\n alt={product.name}\n className=\"lg:w-1/2 w-full lg:h-auto h-64 object-cover object-center rounded\"\n src={product.images[0] || \"/images/placeholder.png\"}\n />\n <div className=\"lg:w-1/2 w-full lg:pl-10 lg:py-6 mt-6 lg:mt-0\">\n {product.brand && (\n <h2 className=\"text-sm text-muted-foreground tracking-widest uppercase\">\n {product.brand}\n </h2>\n )}\n <h1 className=\"text-3xl font-medium mb-1\">{product.name}</h1>\n\n <div className=\"flex mb-4\">\n <span className=\"flex items-center\">\n {renderStars(product.rating)}\n <span className=\"text-muted-foreground ml-3\">\n {product.review_count} {t(\"reviews\", \"Reviews\")}\n </span>\n </span>\n <span className=\"flex ml-3 pl-3 py-2 border-l-2 border-border space-x-2\">\n <a\n href=\"#\"\n className=\"text-muted-foreground hover:text-foreground\"\n >\n <Facebook className=\"w-5 h-5\" />\n </a>\n <a\n href=\"#\"\n className=\"text-muted-foreground hover:text-foreground\"\n >\n <Twitter className=\"w-5 h-5\" />\n </a>\n <a\n href=\"#\"\n className=\"text-muted-foreground hover:text-foreground\"\n >\n <MessageCircle className=\"w-5 h-5\" />\n </a>\n </span>\n </div>\n\n <p className=\"leading-relaxed text-muted-foreground\">\n {product.description}\n </p>\n\n {product.category_name && (\n <p className=\"mt-4 text-sm text-muted-foreground\">\n {t(\"category\", \"Category\")}: {product.category_name}\n </p>\n )}\n\n <div className=\"flex mt-6 items-center pb-5 border-b-2 border-border mb-5\">\n {product.stock > 0 ? (\n <span className=\"text-sm text-green-600 dark:text-green-400\">\n {t(\"inStock\", \"In Stock\")} ({product.stock})\n </span>\n ) : (\n <span className=\"text-sm text-red-600 dark:text-red-400\">\n {t(\"outOfStock\", \"Out of Stock\")}\n </span>\n )}\n </div>\n\n <div className=\"flex items-center\">\n <span className=\"font-medium text-2xl\">\n {formatPrice(price, currency)}\n {product.on_sale && product.sale_price && (\n <span className=\"text-lg text-muted-foreground line-through ml-2\">\n {formatPrice(product.price, currency)}\n </span>\n )}\n </span>\n <Button\n onClick={handleAddToCart}\n className=\"ml-auto\"\n disabled={product.stock === 0}\n >\n {t(\"addToCart\", \"Add to Cart\")}\n </Button>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={handleToggleFavorite}\n className=\"rounded-full ml-4\"\n >\n <Heart\n className={cn(\n \"w-5 h-5\",\n isFavorite(product.id) && \"fill-current text-red-500\"\n )}\n />\n </Button>\n </div>\n </div>\n </div>\n </div>\n </section>\n );\n}\n"
26
+ "content": "import { Star, Heart, Facebook, Twitter, MessageCircle } from \"lucide-react\";\r\nimport { toast } from \"sonner\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport {\r\n useCart,\r\n useFavorites,\r\n formatPrice,\r\n type Product,\r\n} from \"@/modules/ecommerce-core\";\r\nimport constants from \"@/constants/constants.json\";\r\n\r\ninterface ProductDetailSectionProps {\r\n product: Product;\r\n className?: string;\r\n}\r\n\r\nexport function ProductDetailSection({\r\n product,\r\n className,\r\n}: ProductDetailSectionProps) {\r\n const { t } = useTranslation(\"product-detail-section\");\r\n const { addItem } = useCart();\r\n const { isFavorite, addToFavorites, removeFromFavorites } = useFavorites();\r\n const currency = (constants.site as any).currency || \"USD\";\r\n\r\n if (!product) {\r\n return null;\r\n }\r\n\r\n const price = product.on_sale && product.sale_price\r\n ? product.sale_price\r\n : product.price;\r\n\r\n const handleAddToCart = () => {\r\n addItem(product);\r\n toast.success(t(\"addedToCart\", \"Added to cart!\"));\r\n };\r\n\r\n const handleToggleFavorite = () => {\r\n if (isFavorite(product.id)) {\r\n removeFromFavorites(product.id);\r\n } else {\r\n addToFavorites(product);\r\n }\r\n };\r\n\r\n const renderStars = (rating: number) => {\r\n return Array.from({ length: 5 }, (_, i) => (\r\n <Star\r\n key={i}\r\n className={cn(\r\n \"w-4 h-4\",\r\n i < Math.floor(rating) ? \"fill-primary text-primary\" : \"text-primary\"\r\n )}\r\n />\r\n ));\r\n };\r\n\r\n return (\r\n <section className={cn(\"py-24\", className)}>\r\n <div className=\"container px-5 mx-auto\">\r\n <div className=\"lg:w-4/5 mx-auto flex flex-wrap\">\r\n <img\r\n alt={product.name}\r\n className=\"lg:w-1/2 w-full lg:h-auto h-64 object-cover object-center rounded\"\r\n src={product.images[0] || \"/images/placeholder.png\"}\r\n />\r\n <div className=\"lg:w-1/2 w-full lg:pl-10 lg:py-6 mt-6 lg:mt-0\">\r\n {product.brand && (\r\n <h2 className=\"text-sm text-muted-foreground tracking-widest uppercase\">\r\n {product.brand}\r\n </h2>\r\n )}\r\n <h1 className=\"text-3xl font-medium mb-1\">{product.name}</h1>\r\n\r\n <div className=\"flex mb-4\">\r\n <span className=\"flex items-center\">\r\n {renderStars(product.rating)}\r\n <span className=\"text-muted-foreground ml-3\">\r\n {product.review_count} {t(\"reviews\", \"Reviews\")}\r\n </span>\r\n </span>\r\n <span className=\"flex ml-3 pl-3 py-2 border-l-2 border-border space-x-2\">\r\n <a\r\n href=\"#\"\r\n className=\"text-muted-foreground hover:text-foreground\"\r\n >\r\n <Facebook className=\"w-5 h-5\" />\r\n </a>\r\n <a\r\n href=\"#\"\r\n className=\"text-muted-foreground hover:text-foreground\"\r\n >\r\n <Twitter className=\"w-5 h-5\" />\r\n </a>\r\n <a\r\n href=\"#\"\r\n className=\"text-muted-foreground hover:text-foreground\"\r\n >\r\n <MessageCircle className=\"w-5 h-5\" />\r\n </a>\r\n </span>\r\n </div>\r\n\r\n <p className=\"leading-relaxed text-muted-foreground\">\r\n {product.description}\r\n </p>\r\n\r\n {product.category_name && (\r\n <p className=\"mt-4 text-sm text-muted-foreground\">\r\n {t(\"category\", \"Category\")}: {product.category_name}\r\n </p>\r\n )}\r\n\r\n <div className=\"flex mt-6 items-center pb-5 border-b-2 border-border mb-5\">\r\n {product.stock > 0 ? (\r\n <span className=\"text-sm text-green-600 dark:text-green-400\">\r\n {t(\"inStock\", \"In Stock\")} ({product.stock})\r\n </span>\r\n ) : (\r\n <span className=\"text-sm text-red-600 dark:text-red-400\">\r\n {t(\"outOfStock\", \"Out of Stock\")}\r\n </span>\r\n )}\r\n </div>\r\n\r\n <div className=\"flex items-center\">\r\n <span className=\"font-medium text-2xl\">\r\n {formatPrice(price, currency)}\r\n {product.on_sale && product.sale_price && (\r\n <span className=\"text-lg text-muted-foreground line-through ml-2\">\r\n {formatPrice(product.price, currency)}\r\n </span>\r\n )}\r\n </span>\r\n <Button\r\n onClick={handleAddToCart}\r\n className=\"ml-auto\"\r\n disabled={product.stock === 0}\r\n >\r\n {t(\"addToCart\", \"Add to Cart\")}\r\n </Button>\r\n <Button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n onClick={handleToggleFavorite}\r\n className=\"rounded-full ml-4\"\r\n >\r\n <Heart\r\n className={cn(\r\n \"w-5 h-5\",\r\n isFavorite(product.id) && \"fill-current text-red-500\"\r\n )}\r\n />\r\n </Button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </section>\r\n );\r\n}\r\n"
27
27
  },
28
28
  {
29
29
  "path": "product-detail-section/lang/en.json",
30
30
  "type": "registry:lang",
31
31
  "target": "$modules$/product-detail-section/lang/en.json",
32
- "content": "{\n \"reviews\": \"Reviews\",\n \"color\": \"Color\",\n \"size\": \"Size\",\n \"addToCart\": \"Add to Cart\"\n}\n"
32
+ "content": "{\r\n \"reviews\": \"Reviews\",\r\n \"color\": \"Color\",\r\n \"size\": \"Size\",\r\n \"addToCart\": \"Add to Cart\"\r\n}\r\n"
33
33
  },
34
34
  {
35
35
  "path": "product-detail-section/lang/tr.json",
36
36
  "type": "registry:lang",
37
37
  "target": "$modules$/product-detail-section/lang/tr.json",
38
- "content": "{\n \"reviews\": \"Değerlendirme\",\n \"color\": \"Renk\",\n \"size\": \"Beden\",\n \"addToCart\": \"Sepete Ekle\"\n}\n"
38
+ "content": "{\r\n \"reviews\": \"Değerlendirme\",\r\n \"color\": \"Renk\",\r\n \"size\": \"Beden\",\r\n \"addToCart\": \"Sepete Ekle\"\r\n}\r\n"
39
39
  }
40
40
  ],
41
41
  "exports": {
@@ -17,25 +17,25 @@
17
17
  "path": "product-quick-view/product-quick-view.tsx",
18
18
  "type": "registry:component",
19
19
  "target": "$modules$/product-quick-view/product-quick-view.tsx",
20
- "content": "\"use client\";\n\nimport { useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { Link } from \"react-router\";\nimport { toast } from \"sonner\";\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Dialog,\n DialogContent,\n DialogTitle,\n} from \"@/components/ui/dialog\";\nimport { X, Minus, Plus, ShoppingCart, Heart } from \"lucide-react\";\nimport {\n useCart,\n useFavorites,\n formatPrice,\n type Product,\n} from \"@/modules/ecommerce-core\";\nimport constants from \"@/constants/constants.json\";\n\ninterface ProductQuickViewProps {\n product: Product;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n className?: string;\n}\n\nexport function ProductQuickView({\n product,\n open,\n onOpenChange,\n className,\n}: ProductQuickViewProps) {\n const { t } = useTranslation(\"product-quick-view\");\n const { addItem } = useCart();\n const { isFavorite, addToFavorites, removeFromFavorites } = useFavorites();\n const currency = (constants.site as any).currency || \"USD\";\n\n const [selectedImage, setSelectedImage] = useState(0);\n const [quantity, setQuantity] = useState(1);\n\n if (!product) {\n return null;\n }\n\n const price = product.on_sale && product.sale_price\n ? product.sale_price\n : product.price;\n\n const discount = product.on_sale && product.sale_price\n ? Math.round(((product.price - product.sale_price) / product.price) * 100)\n : 0;\n\n const handleAddToCart = () => {\n for (let i = 0; i < quantity; i++) {\n addItem(product);\n }\n toast.success(t(\"addedToCart\", \"Added to cart!\"));\n onOpenChange(false);\n };\n\n const handleToggleFavorite = () => {\n if (isFavorite(product.id)) {\n removeFromFavorites(product.id);\n toast.success(t(\"removedFromFavorites\", \"Removed from favorites\"));\n } else {\n addToFavorites(product);\n toast.success(t(\"addedToFavorites\", \"Added to favorites!\"));\n }\n };\n\n const incrementQuantity = () => setQuantity((q) => q + 1);\n const decrementQuantity = () => setQuantity((q) => Math.max(1, q - 1));\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className={cn(\"sm:max-w-4xl p-0 gap-0 overflow-hidden\", className)}>\n <DialogTitle className=\"sr-only\">{product.name}</DialogTitle>\n\n <button\n onClick={() => onOpenChange(false)}\n className=\"absolute right-4 top-4 z-10 rounded-full bg-background/80 backdrop-blur-sm p-2 hover:bg-background transition-colors\"\n >\n <X className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close</span>\n </button>\n\n <div className=\"grid md:grid-cols-2\">\n {/* Image Gallery */}\n <div className=\"relative bg-muted aspect-square md:aspect-auto md:h-full\">\n <img\n src={product.images[selectedImage] || \"/images/placeholder.png\"}\n alt={product.name}\n className=\"w-full h-full object-cover\"\n />\n\n {discount > 0 && (\n <span className=\"absolute top-4 left-4 bg-destructive text-destructive-foreground text-sm font-semibold px-3 py-1 rounded-full\">\n -{discount}%\n </span>\n )}\n\n {product.images.length > 1 && (\n <div className=\"absolute bottom-4 left-4 flex flex-col gap-2\">\n {product.images.map((image, index) => (\n <button\n key={index}\n onClick={() => setSelectedImage(index)}\n className={cn(\n \"w-14 h-14 rounded-lg overflow-hidden border-2 transition-all bg-background/80 backdrop-blur-sm\",\n selectedImage === index\n ? \"border-primary ring-2 ring-primary/20\"\n : \"border-transparent opacity-70 hover:opacity-100\"\n )}\n >\n <img\n src={image}\n alt={`${product.name} ${index + 1}`}\n className=\"w-full h-full object-cover\"\n />\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* Product Info */}\n <div className=\"p-6 md:p-8 flex flex-col\">\n <div className=\"flex-1\">\n {product.brand && (\n <p className=\"text-sm text-muted-foreground uppercase tracking-wide mb-1\">\n {product.brand}\n </p>\n )}\n <h2 className=\"text-2xl md:text-3xl font-bold mb-2\">\n {product.name}\n </h2>\n\n {/* Price */}\n <div className=\"flex items-center gap-3 mb-4\">\n <span className=\"text-2xl font-bold text-primary\">\n {formatPrice(price, currency)}\n </span>\n {product.on_sale && product.sale_price && (\n <span className=\"text-lg text-muted-foreground line-through\">\n {formatPrice(product.price, currency)}\n </span>\n )}\n </div>\n\n {/* Description */}\n <p className=\"text-muted-foreground mb-6 line-clamp-4\">\n {product.description}\n </p>\n\n {/* Category */}\n {product.category_name && (\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t(\"category\", \"Category\")}: {product.category_name}\n </p>\n )}\n\n {/* Quantity */}\n <div className=\"mb-6\">\n <label className=\"text-sm font-medium mb-2 block\">\n {t(\"quantity\", \"Quantity\")}\n </label>\n <div className=\"flex items-center gap-3\">\n <div className=\"flex items-center border border-border rounded-lg\">\n <button\n onClick={decrementQuantity}\n className=\"p-3 hover:bg-muted transition-colors\"\n disabled={quantity <= 1}\n >\n <Minus className=\"h-4 w-4\" />\n </button>\n <span className=\"w-12 text-center font-medium\">\n {quantity}\n </span>\n <button\n onClick={incrementQuantity}\n className=\"p-3 hover:bg-muted transition-colors\"\n >\n <Plus className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n </div>\n </div>\n\n {/* Actions */}\n <div className=\"space-y-3 pt-4 border-t border-border\">\n <div className=\"flex gap-2\">\n <Button\n onClick={handleAddToCart}\n className=\"flex-1 gap-2\"\n size=\"lg\"\n >\n <ShoppingCart className=\"h-5 w-5\" />\n {t(\"addToCart\", \"Add to Cart\")}\n </Button>\n <Button\n variant=\"outline\"\n size=\"lg\"\n onClick={handleToggleFavorite}\n className=\"px-4\"\n >\n <Heart\n className={cn(\n \"h-5 w-5\",\n isFavorite(product.id) && \"fill-current text-red-500\"\n )}\n />\n </Button>\n </div>\n\n <Link to={`/products/${product.slug}`} className=\"block\">\n <Button\n variant=\"outline\"\n className=\"w-full\"\n size=\"lg\"\n onClick={() => onOpenChange(false)}\n >\n {t(\"viewDetails\", \"View Full Details\")}\n </Button>\n </Link>\n </div>\n </div>\n </div>\n </DialogContent>\n </Dialog>\n );\n}\n"
20
+ "content": "\"use client\";\r\n\r\nimport { useState } from \"react\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { Link } from \"react-router\";\r\nimport { toast } from \"sonner\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport {\r\n Dialog,\r\n DialogContent,\r\n DialogTitle,\r\n} from \"@/components/ui/dialog\";\r\nimport { X, Minus, Plus, ShoppingCart, Heart } from \"lucide-react\";\r\nimport {\r\n useCart,\r\n useFavorites,\r\n formatPrice,\r\n type Product,\r\n} from \"@/modules/ecommerce-core\";\r\nimport constants from \"@/constants/constants.json\";\r\n\r\ninterface ProductQuickViewProps {\r\n product: Product;\r\n open: boolean;\r\n onOpenChange: (open: boolean) => void;\r\n className?: string;\r\n}\r\n\r\nexport function ProductQuickView({\r\n product,\r\n open,\r\n onOpenChange,\r\n className,\r\n}: ProductQuickViewProps) {\r\n const { t } = useTranslation(\"product-quick-view\");\r\n const { addItem } = useCart();\r\n const { isFavorite, addToFavorites, removeFromFavorites } = useFavorites();\r\n const currency = (constants.site as any).currency || \"USD\";\r\n\r\n const [selectedImage, setSelectedImage] = useState(0);\r\n const [quantity, setQuantity] = useState(1);\r\n\r\n if (!product) {\r\n return null;\r\n }\r\n\r\n const price = product.on_sale && product.sale_price\r\n ? product.sale_price\r\n : product.price;\r\n\r\n const discount = product.on_sale && product.sale_price\r\n ? Math.round(((product.price - product.sale_price) / product.price) * 100)\r\n : 0;\r\n\r\n const handleAddToCart = () => {\r\n for (let i = 0; i < quantity; i++) {\r\n addItem(product);\r\n }\r\n toast.success(t(\"addedToCart\", \"Added to cart!\"));\r\n onOpenChange(false);\r\n };\r\n\r\n const handleToggleFavorite = () => {\r\n if (isFavorite(product.id)) {\r\n removeFromFavorites(product.id);\r\n toast.success(t(\"removedFromFavorites\", \"Removed from favorites\"));\r\n } else {\r\n addToFavorites(product);\r\n toast.success(t(\"addedToFavorites\", \"Added to favorites!\"));\r\n }\r\n };\r\n\r\n const incrementQuantity = () => setQuantity((q) => q + 1);\r\n const decrementQuantity = () => setQuantity((q) => Math.max(1, q - 1));\r\n\r\n return (\r\n <Dialog open={open} onOpenChange={onOpenChange}>\r\n <DialogContent className={cn(\"sm:max-w-4xl p-0 gap-0 overflow-hidden\", className)}>\r\n <DialogTitle className=\"sr-only\">{product.name}</DialogTitle>\r\n\r\n <button\r\n onClick={() => onOpenChange(false)}\r\n className=\"absolute right-4 top-4 z-10 rounded-full bg-background/80 backdrop-blur-sm p-2 hover:bg-background transition-colors\"\r\n >\r\n <X className=\"h-4 w-4\" />\r\n <span className=\"sr-only\">Close</span>\r\n </button>\r\n\r\n <div className=\"grid md:grid-cols-2\">\r\n {/* Image Gallery */}\r\n <div className=\"relative bg-muted aspect-square md:aspect-auto md:h-full\">\r\n <img\r\n src={product.images[selectedImage] || \"/images/placeholder.png\"}\r\n alt={product.name}\r\n className=\"w-full h-full object-cover\"\r\n />\r\n\r\n {discount > 0 && (\r\n <span className=\"absolute top-4 left-4 bg-destructive text-destructive-foreground text-sm font-semibold px-3 py-1 rounded-full\">\r\n -{discount}%\r\n </span>\r\n )}\r\n\r\n {product.images.length > 1 && (\r\n <div className=\"absolute bottom-4 left-4 flex flex-col gap-2\">\r\n {product.images.map((image, index) => (\r\n <button\r\n key={index}\r\n onClick={() => setSelectedImage(index)}\r\n className={cn(\r\n \"w-14 h-14 rounded-lg overflow-hidden border-2 transition-all bg-background/80 backdrop-blur-sm\",\r\n selectedImage === index\r\n ? \"border-primary ring-2 ring-primary/20\"\r\n : \"border-transparent opacity-70 hover:opacity-100\"\r\n )}\r\n >\r\n <img\r\n src={image}\r\n alt={`${product.name} ${index + 1}`}\r\n className=\"w-full h-full object-cover\"\r\n />\r\n </button>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Product Info */}\r\n <div className=\"p-6 md:p-8 flex flex-col\">\r\n <div className=\"flex-1\">\r\n {product.brand && (\r\n <p className=\"text-sm text-muted-foreground uppercase tracking-wide mb-1\">\r\n {product.brand}\r\n </p>\r\n )}\r\n <h2 className=\"text-2xl md:text-3xl font-bold mb-2\">\r\n {product.name}\r\n </h2>\r\n\r\n {/* Price */}\r\n <div className=\"flex items-center gap-3 mb-4\">\r\n <span className=\"text-2xl font-bold text-primary\">\r\n {formatPrice(price, currency)}\r\n </span>\r\n {product.on_sale && product.sale_price && (\r\n <span className=\"text-lg text-muted-foreground line-through\">\r\n {formatPrice(product.price, currency)}\r\n </span>\r\n )}\r\n </div>\r\n\r\n {/* Description */}\r\n <p className=\"text-muted-foreground mb-6 line-clamp-4\">\r\n {product.description}\r\n </p>\r\n\r\n {/* Category */}\r\n {product.category_name && (\r\n <p className=\"text-sm text-muted-foreground mb-4\">\r\n {t(\"category\", \"Category\")}: {product.category_name}\r\n </p>\r\n )}\r\n\r\n {/* Quantity */}\r\n <div className=\"mb-6\">\r\n <label className=\"text-sm font-medium mb-2 block\">\r\n {t(\"quantity\", \"Quantity\")}\r\n </label>\r\n <div className=\"flex items-center gap-3\">\r\n <div className=\"flex items-center border border-border rounded-lg\">\r\n <button\r\n onClick={decrementQuantity}\r\n className=\"p-3 hover:bg-muted transition-colors\"\r\n disabled={quantity <= 1}\r\n >\r\n <Minus className=\"h-4 w-4\" />\r\n </button>\r\n <span className=\"w-12 text-center font-medium\">\r\n {quantity}\r\n </span>\r\n <button\r\n onClick={incrementQuantity}\r\n className=\"p-3 hover:bg-muted transition-colors\"\r\n >\r\n <Plus className=\"h-4 w-4\" />\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Actions */}\r\n <div className=\"space-y-3 pt-4 border-t border-border\">\r\n <div className=\"flex gap-2\">\r\n <Button\r\n onClick={handleAddToCart}\r\n className=\"flex-1 gap-2\"\r\n size=\"lg\"\r\n >\r\n <ShoppingCart className=\"h-5 w-5\" />\r\n {t(\"addToCart\", \"Add to Cart\")}\r\n </Button>\r\n <Button\r\n variant=\"outline\"\r\n size=\"lg\"\r\n onClick={handleToggleFavorite}\r\n className=\"px-4\"\r\n >\r\n <Heart\r\n className={cn(\r\n \"h-5 w-5\",\r\n isFavorite(product.id) && \"fill-current text-red-500\"\r\n )}\r\n />\r\n </Button>\r\n </div>\r\n\r\n <Link to={`/products/${product.slug}`} className=\"block\">\r\n <Button\r\n variant=\"outline\"\r\n className=\"w-full\"\r\n size=\"lg\"\r\n onClick={() => onOpenChange(false)}\r\n >\r\n {t(\"viewDetails\", \"View Full Details\")}\r\n </Button>\r\n </Link>\r\n </div>\r\n </div>\r\n </div>\r\n </DialogContent>\r\n </Dialog>\r\n );\r\n}\r\n"
21
21
  },
22
22
  {
23
23
  "path": "product-quick-view/index.ts",
24
24
  "type": "registry:index",
25
25
  "target": "$modules$/product-quick-view/index.ts",
26
- "content": "export * from \"./product-quick-view\";\n"
26
+ "content": "export * from \"./product-quick-view\";\r\n"
27
27
  },
28
28
  {
29
29
  "path": "product-quick-view/lang/en.json",
30
30
  "type": "registry:lang",
31
31
  "target": "$modules$/product-quick-view/lang/en.json",
32
- "content": "{\n \"size\": \"Size\",\n \"color\": \"Color\",\n \"quantity\": \"Quantity\",\n \"addToCart\": \"Add to Cart\",\n \"viewDetails\": \"View Full Details\"\n}\n"
32
+ "content": "{\r\n \"size\": \"Size\",\r\n \"color\": \"Color\",\r\n \"quantity\": \"Quantity\",\r\n \"addToCart\": \"Add to Cart\",\r\n \"viewDetails\": \"View Full Details\"\r\n}\r\n"
33
33
  },
34
34
  {
35
35
  "path": "product-quick-view/lang/tr.json",
36
36
  "type": "registry:lang",
37
37
  "target": "$modules$/product-quick-view/lang/tr.json",
38
- "content": "{\n \"size\": \"Beden\",\n \"color\": \"Renk\",\n \"quantity\": \"Adet\",\n \"addToCart\": \"Sepete Ekle\",\n \"viewDetails\": \"Tüm Detayları Gör\"\n}\n"
38
+ "content": "{\r\n \"size\": \"Beden\",\r\n \"color\": \"Renk\",\r\n \"quantity\": \"Adet\",\r\n \"addToCart\": \"Sepete Ekle\",\r\n \"viewDetails\": \"Tüm Detayları Gör\"\r\n}\r\n"
39
39
  }
40
40
  ],
41
41
  "exports": {
@@ -18,7 +18,7 @@
18
18
  "path": "products-page/index.ts",
19
19
  "type": "registry:index",
20
20
  "target": "$modules$/products-page/index.ts",
21
- "content": "export * from './products-page';\nexport { ProductsPage as default } from './products-page';\n"
21
+ "content": "export * from './products-page';\r\nexport { ProductsPage as default } from './products-page';\r\n"
22
22
  },
23
23
  {
24
24
  "path": "products-page/products-page.tsx",
@@ -30,13 +30,13 @@
30
30
  "path": "products-page/lang/en.json",
31
31
  "type": "registry:lang",
32
32
  "target": "$modules$/products-page/lang/en.json",
33
- "content": "{\n \"pageTitle\": \"Products\",\n \"title\": \"Products\",\n \"allProducts\": \"All Products\",\n \"searchResultsFor\": \"Search Results\",\n \"showing\": \"Showing\",\n \"of\": \"of\",\n \"products\": \"products\",\n \"clearSearch\": \"Clear Search\",\n \"filters\": \"Filters\",\n \"refineSearch\": \"Refine your product search\",\n \"categories\": \"Categories\",\n \"priceRange\": \"Price Range\",\n \"minPrice\": \"Min\",\n \"maxPrice\": \"Max\",\n \"features\": \"Features\",\n \"onSale\": \"On Sale\",\n \"newArrivals\": \"New Arrivals\",\n \"featuredLabel\": \"Featured\",\n \"inStock\": \"In Stock\",\n \"sortBy\": \"Sort by\",\n \"featured\": \"Featured\",\n \"sortPriceLow\": \"Price: Low to High\",\n \"sortPriceHigh\": \"Price: High to Low\",\n \"sortNewest\": \"Newest\",\n \"noProductsFound\": \"No products found matching your criteria.\"\n}\n"
33
+ "content": "{\r\n \"pageTitle\": \"Products\",\r\n \"title\": \"Products\",\r\n \"allProducts\": \"All Products\",\r\n \"searchResultsFor\": \"Search Results\",\r\n \"showing\": \"Showing\",\r\n \"of\": \"of\",\r\n \"products\": \"products\",\r\n \"clearSearch\": \"Clear Search\",\r\n \"filters\": \"Filters\",\r\n \"refineSearch\": \"Refine your product search\",\r\n \"categories\": \"Categories\",\r\n \"priceRange\": \"Price Range\",\r\n \"minPrice\": \"Min\",\r\n \"maxPrice\": \"Max\",\r\n \"features\": \"Features\",\r\n \"onSale\": \"On Sale\",\r\n \"newArrivals\": \"New Arrivals\",\r\n \"featuredLabel\": \"Featured\",\r\n \"inStock\": \"In Stock\",\r\n \"sortBy\": \"Sort by\",\r\n \"featured\": \"Featured\",\r\n \"sortPriceLow\": \"Price: Low to High\",\r\n \"sortPriceHigh\": \"Price: High to Low\",\r\n \"sortNewest\": \"Newest\",\r\n \"noProductsFound\": \"No products found matching your criteria.\"\r\n}\r\n"
34
34
  },
35
35
  {
36
36
  "path": "products-page/lang/tr.json",
37
37
  "type": "registry:lang",
38
38
  "target": "$modules$/products-page/lang/tr.json",
39
- "content": "{\n \"pageTitle\": \"Ürünler\",\n \"title\": \"Ürünler\",\n \"allProducts\": \"Tüm Ürünler\",\n \"searchResultsFor\": \"Arama Sonuçları\",\n \"showing\": \"Gösterilen\",\n \"of\": \"/\",\n \"products\": \"ürün\",\n \"clearSearch\": \"Aramayı Temizle\",\n \"filters\": \"Filtreler\",\n \"refineSearch\": \"Ürün aramanızı daraltın\",\n \"categories\": \"Kategoriler\",\n \"priceRange\": \"Fiyat Aralığı\",\n \"minPrice\": \"Min\",\n \"maxPrice\": \"Max\",\n \"features\": \"Özellikler\",\n \"onSale\": \"İndirimde\",\n \"newArrivals\": \"Yeni Gelenler\",\n \"featuredLabel\": \"Öne Çıkan\",\n \"inStock\": \"Stokta\",\n \"sortBy\": \"Sırala\",\n \"featured\": \"Öne Çıkan\",\n \"sortPriceLow\": \"Fiyat: Düşükten Yükseğe\",\n \"sortPriceHigh\": \"Fiyat: Yüksekten Düşüğe\",\n \"sortNewest\": \"En Yeni\",\n \"noProductsFound\": \"Kriterlerinize uygun ürün bulunamadı.\"\n}\n"
39
+ "content": "{\r\n \"pageTitle\": \"Ürünler\",\r\n \"title\": \"Ürünler\",\r\n \"allProducts\": \"Tüm Ürünler\",\r\n \"searchResultsFor\": \"Arama Sonuçları\",\r\n \"showing\": \"Gösterilen\",\r\n \"of\": \"/\",\r\n \"products\": \"ürün\",\r\n \"clearSearch\": \"Aramayı Temizle\",\r\n \"filters\": \"Filtreler\",\r\n \"refineSearch\": \"Ürün aramanızı daraltın\",\r\n \"categories\": \"Kategoriler\",\r\n \"priceRange\": \"Fiyat Aralığı\",\r\n \"minPrice\": \"Min\",\r\n \"maxPrice\": \"Max\",\r\n \"features\": \"Özellikler\",\r\n \"onSale\": \"İndirimde\",\r\n \"newArrivals\": \"Yeni Gelenler\",\r\n \"featuredLabel\": \"Öne Çıkan\",\r\n \"inStock\": \"Stokta\",\r\n \"sortBy\": \"Sırala\",\r\n \"featured\": \"Öne Çıkan\",\r\n \"sortPriceLow\": \"Fiyat: Düşükten Yükseğe\",\r\n \"sortPriceHigh\": \"Fiyat: Yüksekten Düşüğe\",\r\n \"sortNewest\": \"En Yeni\",\r\n \"noProductsFound\": \"Kriterlerinize uygun ürün bulunamadı.\"\r\n}\r\n"
40
40
  }
41
41
  ],
42
42
  "exports": {
@@ -13,25 +13,25 @@
13
13
  "path": "reading-progress/reading-progress.tsx",
14
14
  "type": "registry:component",
15
15
  "target": "$modules$/reading-progress/reading-progress.tsx",
16
- "content": "\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { motion, useScroll, useSpring } from \"motion/react\";\nimport { cn } from \"@/lib/utils\";\n\ninterface ReadingProgressProps {\n color?: string;\n height?: number;\n showPercentage?: boolean;\n className?: string;\n}\n\nexport function ReadingProgress({\n color,\n height = 3,\n showPercentage = false,\n className,\n}: ReadingProgressProps) {\n const [mounted] = useState(() => typeof window !== \"undefined\");\n const { scrollYProgress } = useScroll();\n const scaleX = useSpring(scrollYProgress, {\n stiffness: 100,\n damping: 30,\n restDelta: 0.001,\n });\n\n const [percentage, setPercentage] = useState(0);\n\n useEffect(() => {\n if (!showPercentage) return;\n\n const unsubscribe = scrollYProgress.on(\"change\", (latest) => {\n setPercentage(Math.round(latest * 100));\n });\n\n return () => unsubscribe();\n }, [scrollYProgress, showPercentage]);\n\n if (!mounted) return null;\n\n return (\n <>\n <motion.div\n className={cn(\"fixed top-0 left-0 right-0 z-50 origin-left\", className)}\n style={{\n scaleX,\n height,\n backgroundColor: color || \"var(--primary)\",\n }}\n />\n {showPercentage && (\n <div\n className=\"fixed top-4 right-4 z-50 bg-background/80 backdrop-blur-sm rounded-full px-3 py-1 text-sm font-medium border border-border shadow-sm\"\n >\n {percentage}%\n </div>\n )}\n </>\n );\n}\n"
16
+ "content": "\"use client\";\r\n\r\nimport { useEffect, useState } from \"react\";\r\nimport { motion, useScroll, useSpring } from \"motion/react\";\r\nimport { cn } from \"@/lib/utils\";\r\n\r\ninterface ReadingProgressProps {\r\n color?: string;\r\n height?: number;\r\n showPercentage?: boolean;\r\n className?: string;\r\n}\r\n\r\nexport function ReadingProgress({\r\n color,\r\n height = 3,\r\n showPercentage = false,\r\n className,\r\n}: ReadingProgressProps) {\r\n const [mounted] = useState(() => typeof window !== \"undefined\");\r\n const { scrollYProgress } = useScroll();\r\n const scaleX = useSpring(scrollYProgress, {\r\n stiffness: 100,\r\n damping: 30,\r\n restDelta: 0.001,\r\n });\r\n\r\n const [percentage, setPercentage] = useState(0);\r\n\r\n useEffect(() => {\r\n if (!showPercentage) return;\r\n\r\n const unsubscribe = scrollYProgress.on(\"change\", (latest) => {\r\n setPercentage(Math.round(latest * 100));\r\n });\r\n\r\n return () => unsubscribe();\r\n }, [scrollYProgress, showPercentage]);\r\n\r\n if (!mounted) return null;\r\n\r\n return (\r\n <>\r\n <motion.div\r\n className={cn(\"fixed top-0 left-0 right-0 z-50 origin-left\", className)}\r\n style={{\r\n scaleX,\r\n height,\r\n backgroundColor: color || \"var(--primary)\",\r\n }}\r\n />\r\n {showPercentage && (\r\n <div\r\n className=\"fixed top-4 right-4 z-50 bg-background/80 backdrop-blur-sm rounded-full px-3 py-1 text-sm font-medium border border-border shadow-sm\"\r\n >\r\n {percentage}%\r\n </div>\r\n )}\r\n </>\r\n );\r\n}\r\n"
17
17
  },
18
18
  {
19
19
  "path": "reading-progress/index.ts",
20
20
  "type": "registry:index",
21
21
  "target": "$modules$/reading-progress/index.ts",
22
- "content": "export * from \"./reading-progress\";\n"
22
+ "content": "export * from \"./reading-progress\";\r\n"
23
23
  },
24
24
  {
25
25
  "path": "reading-progress/lang/en.json",
26
26
  "type": "registry:lang",
27
27
  "target": "$modules$/reading-progress/lang/en.json",
28
- "content": "{\n \"progress\": \"Reading progress\"\n}\n"
28
+ "content": "{\r\n \"progress\": \"Reading progress\"\r\n}\r\n"
29
29
  },
30
30
  {
31
31
  "path": "reading-progress/lang/tr.json",
32
32
  "type": "registry:lang",
33
33
  "target": "$modules$/reading-progress/lang/tr.json",
34
- "content": "{\n \"progress\": \"Okuma ilerlemesi\"\n}\n"
34
+ "content": "{\r\n \"progress\": \"Okuma ilerlemesi\"\r\n}\r\n"
35
35
  }
36
36
  ],
37
37
  "exports": {
@@ -17,25 +17,25 @@
17
17
  "path": "register-page-split/index.ts",
18
18
  "type": "registry:index",
19
19
  "target": "$modules$/register-page-split/index.ts",
20
- "content": "export * from './register-page-split';\nexport { default } from './register-page-split';\n"
20
+ "content": "export * from './register-page-split';\r\nexport { default } from './register-page-split';\r\n"
21
21
  },
22
22
  {
23
23
  "path": "register-page-split/register-page-split.tsx",
24
24
  "type": "registry:page",
25
25
  "target": "$modules$/register-page-split/register-page-split.tsx",
26
- "content": "import { useState } from \"react\";\nimport { Link, useNavigate } from \"react-router\";\nimport { toast } from \"sonner\";\nimport { useTranslation } from \"react-i18next\";\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 { useAuth } from \"@/modules/auth-core\";\nimport { getErrorMessage } from \"@/modules/api\";\n\ninterface RegisterPageSplitProps {\n image?: string;\n}\n\nexport function RegisterPageSplit({\n image = \"/images/placeholder.png\",\n}: RegisterPageSplitProps) {\n const { t } = useTranslation(\"register-page-split\");\n usePageTitle({ title: t(\"title\", \"Create Account\") });\n const navigate = useNavigate();\n const { register } = useAuth();\n\n const [username, setUsername] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [confirmPassword, setConfirmPassword] = useState(\"\");\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n\n // Validate passwords match\n if (password !== confirmPassword) {\n setError(t(\"passwordMismatch\", \"Passwords do not match\"));\n return;\n }\n\n setIsLoading(true);\n\n try {\n await register(username, email, password);\n\n toast.success(t(\"registerSuccess\", \"Account created successfully!\"), {\n description: t(\"checkEmail\", \"Please check your email to verify your account.\"),\n });\n\n // Navigate to login page after successful registration\n navigate(\"/login\", {\n state: {\n message: t(\"verifyEmail\", \"Please verify your email before logging in.\"),\n email\n }\n });\n } catch (err) {\n const errorMessage = getErrorMessage(\n err,\n t(\"registerError\", \"Registration failed. Please try again.\")\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\", \"Create Account\")}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"subtitle\", \"Sign up to get started\")}\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\">{t(\"username\", \"Username\")}</Label>\n <Input\n required\n id=\"username\"\n type=\"text\"\n autoComplete=\"username\"\n placeholder={t(\"usernamePlaceholder\", \"johndoe\")}\n value={username}\n onChange={(e) => setUsername(e.target.value)}\n disabled={isLoading}\n />\n </div>\n\n <div className=\"grid gap-2\">\n <Label htmlFor=\"email\">{t(\"email\", \"Email\")}</Label>\n <Input\n required\n id=\"email\"\n type=\"email\"\n autoComplete=\"email\"\n placeholder={t(\"emailPlaceholder\", \"you@example.com\")}\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n disabled={isLoading}\n />\n </div>\n\n <div className=\"grid gap-2\">\n <Label htmlFor=\"password\">{t(\"password\", \"Password\")}</Label>\n <Input\n required\n id=\"password\"\n type=\"password\"\n autoComplete=\"new-password\"\n placeholder=\"••••••••\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n disabled={isLoading}\n minLength={8}\n />\n </div>\n\n <div className=\"grid gap-2\">\n <Label htmlFor=\"confirm-password\">{t(\"confirmPassword\", \"Confirm Password\")}</Label>\n <Input\n required\n id=\"confirm-password\"\n type=\"password\"\n autoComplete=\"new-password\"\n placeholder=\"••••••••\"\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n disabled={isLoading}\n minLength={8}\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(\"creatingAccount\", \"Creating account...\")}\n </>\n ) : (\n t(\"signUp\", \"Sign Up\")\n )}\n </Button>\n </form>\n\n <div className=\"text-sm text-center\">\n <p>\n {t(\"hasAccount\", \"Already have an account?\")}{\" \"}\n <Link to=\"/login\" className=\"underline\">\n {t(\"signIn\", \"Sign in\")}\n </Link>\n </p>\n </div>\n\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\", \"Register 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 RegisterPageSplit;\n"
26
+ "content": "import { useState } from \"react\";\r\nimport { Link, useNavigate } from \"react-router\";\r\nimport { toast } from \"sonner\";\r\nimport { useTranslation } from \"react-i18next\";\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 { useAuth } from \"@/modules/auth-core\";\r\nimport { getErrorMessage } from \"@/modules/api\";\r\n\r\ninterface RegisterPageSplitProps {\r\n image?: string;\r\n}\r\n\r\nexport function RegisterPageSplit({\r\n image = \"/images/placeholder.png\",\r\n}: RegisterPageSplitProps) {\r\n const { t } = useTranslation(\"register-page-split\");\r\n usePageTitle({ title: t(\"title\", \"Create Account\") });\r\n const navigate = useNavigate();\r\n const { register } = useAuth();\r\n\r\n const [username, setUsername] = useState(\"\");\r\n const [email, setEmail] = useState(\"\");\r\n const [password, setPassword] = useState(\"\");\r\n const [confirmPassword, setConfirmPassword] = useState(\"\");\r\n const [isLoading, setIsLoading] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setError(null);\r\n\r\n // Validate passwords match\r\n if (password !== confirmPassword) {\r\n setError(t(\"passwordMismatch\", \"Passwords do not match\"));\r\n return;\r\n }\r\n\r\n setIsLoading(true);\r\n\r\n try {\r\n await register(username, email, password);\r\n\r\n toast.success(t(\"registerSuccess\", \"Account created successfully!\"), {\r\n description: t(\"checkEmail\", \"Please check your email to verify your account.\"),\r\n });\r\n\r\n // Navigate to login page after successful registration\r\n navigate(\"/login\", {\r\n state: {\r\n message: t(\"verifyEmail\", \"Please verify your email before logging in.\"),\r\n email\r\n }\r\n });\r\n } catch (err) {\r\n const errorMessage = getErrorMessage(\r\n err,\r\n t(\"registerError\", \"Registration failed. Please try again.\")\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\", \"Create Account\")}\r\n </h1>\r\n <p className=\"text-sm text-muted-foreground\">\r\n {t(\"subtitle\", \"Sign up to get started\")}\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\">{t(\"username\", \"Username\")}</Label>\r\n <Input\r\n required\r\n id=\"username\"\r\n type=\"text\"\r\n autoComplete=\"username\"\r\n placeholder={t(\"usernamePlaceholder\", \"johndoe\")}\r\n value={username}\r\n onChange={(e) => setUsername(e.target.value)}\r\n disabled={isLoading}\r\n />\r\n </div>\r\n\r\n <div className=\"grid gap-2\">\r\n <Label htmlFor=\"email\">{t(\"email\", \"Email\")}</Label>\r\n <Input\r\n required\r\n id=\"email\"\r\n type=\"email\"\r\n autoComplete=\"email\"\r\n placeholder={t(\"emailPlaceholder\", \"you@example.com\")}\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n disabled={isLoading}\r\n />\r\n </div>\r\n\r\n <div className=\"grid gap-2\">\r\n <Label htmlFor=\"password\">{t(\"password\", \"Password\")}</Label>\r\n <Input\r\n required\r\n id=\"password\"\r\n type=\"password\"\r\n autoComplete=\"new-password\"\r\n placeholder=\"••••••••\"\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n disabled={isLoading}\r\n minLength={8}\r\n />\r\n </div>\r\n\r\n <div className=\"grid gap-2\">\r\n <Label htmlFor=\"confirm-password\">{t(\"confirmPassword\", \"Confirm Password\")}</Label>\r\n <Input\r\n required\r\n id=\"confirm-password\"\r\n type=\"password\"\r\n autoComplete=\"new-password\"\r\n placeholder=\"••••••••\"\r\n value={confirmPassword}\r\n onChange={(e) => setConfirmPassword(e.target.value)}\r\n disabled={isLoading}\r\n minLength={8}\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(\"creatingAccount\", \"Creating account...\")}\r\n </>\r\n ) : (\r\n t(\"signUp\", \"Sign Up\")\r\n )}\r\n </Button>\r\n </form>\r\n\r\n <div className=\"text-sm text-center\">\r\n <p>\r\n {t(\"hasAccount\", \"Already have an account?\")}{\" \"}\r\n <Link to=\"/login\" className=\"underline\">\r\n {t(\"signIn\", \"Sign in\")}\r\n </Link>\r\n </p>\r\n </div>\r\n\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\", \"Register 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 RegisterPageSplit;\r\n"
27
27
  },
28
28
  {
29
29
  "path": "register-page-split/lang/en.json",
30
30
  "type": "registry:lang",
31
31
  "target": "$modules$/register-page-split/lang/en.json",
32
- "content": "{\n \"title\": \"Create Account\",\n \"subtitle\": \"Sign up to get started\",\n \"username\": \"Username\",\n \"usernamePlaceholder\": \"johndoe\",\n \"email\": \"Email\",\n \"emailPlaceholder\": \"you@example.com\",\n \"password\": \"Password\",\n \"confirmPassword\": \"Confirm Password\",\n \"passwordMismatch\": \"Passwords do not match\",\n \"signUp\": \"Sign Up\",\n \"creatingAccount\": \"Creating account...\",\n \"registerSuccess\": \"Account created successfully!\",\n \"checkEmail\": \"Please check your email to verify your account.\",\n \"verifyEmail\": \"Please verify your email before logging in.\",\n \"registerError\": \"Registration failed. Please try again.\",\n \"hasAccount\": \"Already have an account?\",\n \"signIn\": \"Sign in\",\n \"copyright\": \"All rights reserved.\",\n \"imageAlt\": \"Register background\"\n}\n"
32
+ "content": "{\r\n \"title\": \"Create Account\",\r\n \"subtitle\": \"Sign up to get started\",\r\n \"username\": \"Username\",\r\n \"usernamePlaceholder\": \"johndoe\",\r\n \"email\": \"Email\",\r\n \"emailPlaceholder\": \"you@example.com\",\r\n \"password\": \"Password\",\r\n \"confirmPassword\": \"Confirm Password\",\r\n \"passwordMismatch\": \"Passwords do not match\",\r\n \"signUp\": \"Sign Up\",\r\n \"creatingAccount\": \"Creating account...\",\r\n \"registerSuccess\": \"Account created successfully!\",\r\n \"checkEmail\": \"Please check your email to verify your account.\",\r\n \"verifyEmail\": \"Please verify your email before logging in.\",\r\n \"registerError\": \"Registration failed. Please try again.\",\r\n \"hasAccount\": \"Already have an account?\",\r\n \"signIn\": \"Sign in\",\r\n \"copyright\": \"All rights reserved.\",\r\n \"imageAlt\": \"Register background\"\r\n}\r\n"
33
33
  },
34
34
  {
35
35
  "path": "register-page-split/lang/tr.json",
36
36
  "type": "registry:lang",
37
37
  "target": "$modules$/register-page-split/lang/tr.json",
38
- "content": "{\n \"title\": \"Hesap Oluştur\",\n \"subtitle\": \"Başlamak için kaydolun\",\n \"username\": \"Kullanıcı Adı\",\n \"usernamePlaceholder\": \"ahmetyilmaz\",\n \"email\": \"E-posta\",\n \"emailPlaceholder\": \"ornek@email.com\",\n \"password\": \"Şifre\",\n \"confirmPassword\": \"Şifre Onayı\",\n \"passwordMismatch\": \"Şifreler eşleşmiyor\",\n \"signUp\": \"Kaydol\",\n \"creatingAccount\": \"Hesap oluşturuluyor...\",\n \"registerSuccess\": \"Hesap başarıyla oluşturuldu!\",\n \"checkEmail\": \"Lütfen hesabınızı doğrulamak için e-postanızı kontrol edin.\",\n \"verifyEmail\": \"Lütfen giriş yapmadan önce e-postanızı doğrulayın.\",\n \"registerError\": \"Kayıt başarısız. Lütfen tekrar deneyin.\",\n \"hasAccount\": \"Zaten hesabınız var mı?\",\n \"signIn\": \"Giriş yap\",\n \"copyright\": \"Tüm hakları saklıdır.\",\n \"imageAlt\": \"Kayıt arka planı\"\n}\n"
38
+ "content": "{\r\n \"title\": \"Hesap Oluştur\",\r\n \"subtitle\": \"Başlamak için kaydolun\",\r\n \"username\": \"Kullanıcı Adı\",\r\n \"usernamePlaceholder\": \"ahmetyilmaz\",\r\n \"email\": \"E-posta\",\r\n \"emailPlaceholder\": \"ornek@email.com\",\r\n \"password\": \"Şifre\",\r\n \"confirmPassword\": \"Şifre Onayı\",\r\n \"passwordMismatch\": \"Şifreler eşleşmiyor\",\r\n \"signUp\": \"Kaydol\",\r\n \"creatingAccount\": \"Hesap oluşturuluyor...\",\r\n \"registerSuccess\": \"Hesap başarıyla oluşturuldu!\",\r\n \"checkEmail\": \"Lütfen hesabınızı doğrulamak için e-postanızı kontrol edin.\",\r\n \"verifyEmail\": \"Lütfen giriş yapmadan önce e-postanızı doğrulayın.\",\r\n \"registerError\": \"Kayıt başarısız. Lütfen tekrar deneyin.\",\r\n \"hasAccount\": \"Zaten hesabınız var mı?\",\r\n \"signIn\": \"Giriş yap\",\r\n \"copyright\": \"Tüm hakları saklıdır.\",\r\n \"imageAlt\": \"Kayıt arka planı\"\r\n}\r\n"
39
39
  }
40
40
  ],
41
41
  "exports": {
@@ -17,25 +17,25 @@
17
17
  "path": "register-page/index.ts",
18
18
  "type": "registry:index",
19
19
  "target": "$modules$/register-page/index.ts",
20
- "content": "export * from './register-page';\nexport { default } from './register-page';\n"
20
+ "content": "export * from './register-page';\r\nexport { default } from './register-page';\r\n"
21
21
  },
22
22
  {
23
23
  "path": "register-page/register-page.tsx",
24
24
  "type": "registry:page",
25
25
  "target": "$modules$/register-page/register-page.tsx",
26
- "content": "import { useState, useEffect } from \"react\";\nimport { Link, useNavigate } from \"react-router\";\nimport { toast } from \"sonner\";\nimport { Layout } from \"@/components/Layout\";\nimport { usePageTitle } from \"@/hooks/use-page-title\";\nimport { useTranslation } from \"react-i18next\";\nimport { useAuth } from \"@/modules/auth-core\";\nimport { getErrorMessage } from \"@/modules/api\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\nimport { UserPlus, Eye, EyeOff, CheckCircle } from \"lucide-react\";\n\nexport function RegisterPage() {\n const { t } = useTranslation(\"register-page\");\n usePageTitle({ title: t(\"title\", \"Create Account\") });\n\n const navigate = useNavigate();\n const { register, isAuthenticated } = useAuth();\n\n const [formData, setFormData] = useState({\n username: \"\",\n email: \"\",\n password: \"\",\n confirmPassword: \"\",\n });\n const [showPassword, setShowPassword] = useState(false);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [success, setSuccess] = useState(false);\n\n // Redirect if already authenticated\n useEffect(() => {\n if (isAuthenticated) {\n navigate(\"/\", { replace: true });\n }\n }, [isAuthenticated, navigate]);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setIsSubmitting(true);\n setError(null);\n\n // Validate passwords match\n if (formData.password !== formData.confirmPassword) {\n setError(t(\"passwordMismatch\", \"Passwords do not match\"));\n toast.error(t(\"toastErrorTitle\", \"Registration failed\"), {\n description: t(\"passwordMismatch\", \"Passwords do not match\"),\n });\n setIsSubmitting(false);\n return;\n }\n\n try {\n await register(formData.username, formData.email, formData.password);\n setSuccess(true);\n toast.success(t(\"toastSuccessTitle\", \"Account created!\"), {\n description: t(\n \"toastSuccessDesc\",\n \"Please check your email to verify your account.\",\n ),\n });\n } catch (err) {\n const errorMessage = getErrorMessage(err, t(\"errorGeneric\", \"Registration failed. Please try again.\"));\n setError(errorMessage);\n toast.error(t(\"toastErrorTitle\", \"Registration failed\"), {\n description: errorMessage,\n });\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setFormData((prev) => ({\n ...prev,\n [e.target.name]: e.target.value,\n }));\n };\n\n if (success) {\n return (\n <Layout>\n <div className=\"min-h-screen bg-muted/30 py-12\">\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4\">\n <div className=\"max-w-md mx-auto\">\n <Card>\n <CardContent className=\"pt-6\">\n <div className=\"text-center space-y-4\">\n <CheckCircle className=\"w-16 h-16 text-green-500 mx-auto\" />\n <h2 className=\"text-2xl font-bold text-foreground\">\n {t(\"successTitle\", \"Account Created!\")}\n </h2>\n <p className=\"text-muted-foreground\">\n {t(\"successMessage\", \"Please check your email to verify your account.\")}\n </p>\n <Button asChild className=\"mt-4\">\n <Link to=\"/login\">{t(\"goToLogin\", \"Go to Login\")}</Link>\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n </Layout>\n );\n }\n\n return (\n <Layout>\n <div className=\"min-h-screen bg-muted/30 py-12\">\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4\">\n {/* Hero Section */}\n <div className=\"text-center mb-12\">\n <h1 className=\"text-4xl font-bold text-foreground mb-4\">\n {t(\"title\", \"Create Account\")}\n </h1>\n <div className=\"w-16 h-1 bg-primary mx-auto mb-6\"></div>\n <p className=\"text-lg text-muted-foreground max-w-xl mx-auto\">\n {t(\"description\", \"Create an account to get started\")}\n </p>\n </div>\n\n <div className=\"max-w-md mx-auto\">\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <UserPlus className=\"w-5 h-5 text-primary\" />\n {t(\"cardTitle\", \"Sign Up\")}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n <div>\n <Label htmlFor=\"username\">{t(\"username\", \"Username\")} *</Label>\n <Input\n id=\"username\"\n name=\"username\"\n type=\"text\"\n value={formData.username}\n onChange={handleChange}\n placeholder={t(\"usernamePlaceholder\", \"Enter your username\")}\n required\n className=\"mt-1\"\n autoComplete=\"username\"\n />\n </div>\n\n <div>\n <Label htmlFor=\"email\">{t(\"email\", \"Email\")} *</Label>\n <Input\n id=\"email\"\n name=\"email\"\n type=\"email\"\n value={formData.email}\n onChange={handleChange}\n placeholder={t(\"emailPlaceholder\", \"Enter your email\")}\n required\n className=\"mt-1\"\n autoComplete=\"email\"\n />\n </div>\n\n <div>\n <Label htmlFor=\"password\">{t(\"password\", \"Password\")} *</Label>\n <div className=\"relative\">\n <Input\n id=\"password\"\n name=\"password\"\n type={showPassword ? \"text\" : \"password\"}\n value={formData.password}\n onChange={handleChange}\n placeholder={t(\"passwordPlaceholder\", \"Enter password\")}\n required\n className=\"mt-1 pr-10\"\n autoComplete=\"new-password\"\n />\n <button\n type=\"button\"\n onClick={() => setShowPassword(!showPassword)}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground\"\n >\n {showPassword ? (\n <EyeOff className=\"w-4 h-4\" />\n ) : (\n <Eye className=\"w-4 h-4\" />\n )}\n </button>\n </div>\n </div>\n\n <div>\n <Label htmlFor=\"confirmPassword\">\n {t(\"confirmPassword\", \"Confirm Password\")} *\n </Label>\n <Input\n id=\"confirmPassword\"\n name=\"confirmPassword\"\n type={showPassword ? \"text\" : \"password\"}\n value={formData.confirmPassword}\n onChange={handleChange}\n placeholder={t(\"confirmPasswordPlaceholder\", \"Confirm your password\")}\n required\n className=\"mt-1\"\n autoComplete=\"new-password\"\n />\n </div>\n\n {error && (\n <div className=\"p-4 bg-red-50 border border-red-200 rounded-lg\">\n <p className=\"text-red-800 text-sm font-medium\">\n {error}\n </p>\n </div>\n )}\n\n <Button\n type=\"submit\"\n size=\"lg\"\n className=\"w-full\"\n disabled={isSubmitting}\n >\n {isSubmitting ? (\n <>\n <div className=\"w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin mr-2\" />\n {t(\"submitting\", \"Creating account...\")}\n </>\n ) : (\n t(\"submit\", \"Create Account\")\n )}\n </Button>\n\n <div className=\"text-center text-sm text-muted-foreground\">\n {t(\"hasAccount\", \"Already have an account?\")}{\" \"}\n <Link\n to=\"/login\"\n className=\"text-primary hover:underline font-medium\"\n >\n {t(\"loginLink\", \"Sign in\")}\n </Link>\n </div>\n </form>\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n </Layout>\n );\n}\n\nexport default RegisterPage;\n"
26
+ "content": "import { useState, useEffect } from \"react\";\r\nimport { Link, useNavigate } from \"react-router\";\r\nimport { toast } from \"sonner\";\r\nimport { Layout } from \"@/components/Layout\";\r\nimport { usePageTitle } from \"@/hooks/use-page-title\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { useAuth } from \"@/modules/auth-core\";\r\nimport { getErrorMessage } from \"@/modules/api\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Label } from \"@/components/ui/label\";\r\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/components/ui/card\";\r\nimport { UserPlus, Eye, EyeOff, CheckCircle } from \"lucide-react\";\r\n\r\nexport function RegisterPage() {\r\n const { t } = useTranslation(\"register-page\");\r\n usePageTitle({ title: t(\"title\", \"Create Account\") });\r\n\r\n const navigate = useNavigate();\r\n const { register, isAuthenticated } = useAuth();\r\n\r\n const [formData, setFormData] = useState({\r\n username: \"\",\r\n email: \"\",\r\n password: \"\",\r\n confirmPassword: \"\",\r\n });\r\n const [showPassword, setShowPassword] = useState(false);\r\n const [isSubmitting, setIsSubmitting] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [success, setSuccess] = useState(false);\r\n\r\n // Redirect if already authenticated\r\n useEffect(() => {\r\n if (isAuthenticated) {\r\n navigate(\"/\", { replace: true });\r\n }\r\n }, [isAuthenticated, navigate]);\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setIsSubmitting(true);\r\n setError(null);\r\n\r\n // Validate passwords match\r\n if (formData.password !== formData.confirmPassword) {\r\n setError(t(\"passwordMismatch\", \"Passwords do not match\"));\r\n toast.error(t(\"toastErrorTitle\", \"Registration failed\"), {\r\n description: t(\"passwordMismatch\", \"Passwords do not match\"),\r\n });\r\n setIsSubmitting(false);\r\n return;\r\n }\r\n\r\n try {\r\n await register(formData.username, formData.email, formData.password);\r\n setSuccess(true);\r\n toast.success(t(\"toastSuccessTitle\", \"Account created!\"), {\r\n description: t(\r\n \"toastSuccessDesc\",\r\n \"Please check your email to verify your account.\",\r\n ),\r\n });\r\n } catch (err) {\r\n const errorMessage = getErrorMessage(err, t(\"errorGeneric\", \"Registration failed. Please try again.\"));\r\n setError(errorMessage);\r\n toast.error(t(\"toastErrorTitle\", \"Registration failed\"), {\r\n description: errorMessage,\r\n });\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n };\r\n\r\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\r\n setFormData((prev) => ({\r\n ...prev,\r\n [e.target.name]: e.target.value,\r\n }));\r\n };\r\n\r\n if (success) {\r\n return (\r\n <Layout>\r\n <div className=\"min-h-screen bg-muted/30 py-12\">\r\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4\">\r\n <div className=\"max-w-md mx-auto\">\r\n <Card>\r\n <CardContent className=\"pt-6\">\r\n <div className=\"text-center space-y-4\">\r\n <CheckCircle className=\"w-16 h-16 text-green-500 mx-auto\" />\r\n <h2 className=\"text-2xl font-bold text-foreground\">\r\n {t(\"successTitle\", \"Account Created!\")}\r\n </h2>\r\n <p className=\"text-muted-foreground\">\r\n {t(\"successMessage\", \"Please check your email to verify your account.\")}\r\n </p>\r\n <Button asChild className=\"mt-4\">\r\n <Link to=\"/login\">{t(\"goToLogin\", \"Go to Login\")}</Link>\r\n </Button>\r\n </div>\r\n </CardContent>\r\n </Card>\r\n </div>\r\n </div>\r\n </div>\r\n </Layout>\r\n );\r\n }\r\n\r\n return (\r\n <Layout>\r\n <div className=\"min-h-screen bg-muted/30 py-12\">\r\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4\">\r\n {/* Hero Section */}\r\n <div className=\"text-center mb-12\">\r\n <h1 className=\"text-4xl font-bold text-foreground mb-4\">\r\n {t(\"title\", \"Create Account\")}\r\n </h1>\r\n <div className=\"w-16 h-1 bg-primary mx-auto mb-6\"></div>\r\n <p className=\"text-lg text-muted-foreground max-w-xl mx-auto\">\r\n {t(\"description\", \"Create an account to get started\")}\r\n </p>\r\n </div>\r\n\r\n <div className=\"max-w-md mx-auto\">\r\n <Card>\r\n <CardHeader>\r\n <CardTitle className=\"flex items-center gap-2\">\r\n <UserPlus className=\"w-5 h-5 text-primary\" />\r\n {t(\"cardTitle\", \"Sign Up\")}\r\n </CardTitle>\r\n </CardHeader>\r\n <CardContent>\r\n <form onSubmit={handleSubmit} className=\"space-y-6\">\r\n <div>\r\n <Label htmlFor=\"username\">{t(\"username\", \"Username\")} *</Label>\r\n <Input\r\n id=\"username\"\r\n name=\"username\"\r\n type=\"text\"\r\n value={formData.username}\r\n onChange={handleChange}\r\n placeholder={t(\"usernamePlaceholder\", \"Enter your username\")}\r\n required\r\n className=\"mt-1\"\r\n autoComplete=\"username\"\r\n />\r\n </div>\r\n\r\n <div>\r\n <Label htmlFor=\"email\">{t(\"email\", \"Email\")} *</Label>\r\n <Input\r\n id=\"email\"\r\n name=\"email\"\r\n type=\"email\"\r\n value={formData.email}\r\n onChange={handleChange}\r\n placeholder={t(\"emailPlaceholder\", \"Enter your email\")}\r\n required\r\n className=\"mt-1\"\r\n autoComplete=\"email\"\r\n />\r\n </div>\r\n\r\n <div>\r\n <Label htmlFor=\"password\">{t(\"password\", \"Password\")} *</Label>\r\n <div className=\"relative\">\r\n <Input\r\n id=\"password\"\r\n name=\"password\"\r\n type={showPassword ? \"text\" : \"password\"}\r\n value={formData.password}\r\n onChange={handleChange}\r\n placeholder={t(\"passwordPlaceholder\", \"Enter password\")}\r\n required\r\n className=\"mt-1 pr-10\"\r\n autoComplete=\"new-password\"\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={() => setShowPassword(!showPassword)}\r\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground\"\r\n >\r\n {showPassword ? (\r\n <EyeOff className=\"w-4 h-4\" />\r\n ) : (\r\n <Eye className=\"w-4 h-4\" />\r\n )}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div>\r\n <Label htmlFor=\"confirmPassword\">\r\n {t(\"confirmPassword\", \"Confirm Password\")} *\r\n </Label>\r\n <Input\r\n id=\"confirmPassword\"\r\n name=\"confirmPassword\"\r\n type={showPassword ? \"text\" : \"password\"}\r\n value={formData.confirmPassword}\r\n onChange={handleChange}\r\n placeholder={t(\"confirmPasswordPlaceholder\", \"Confirm your password\")}\r\n required\r\n className=\"mt-1\"\r\n autoComplete=\"new-password\"\r\n />\r\n </div>\r\n\r\n {error && (\r\n <div className=\"p-4 bg-red-50 border border-red-200 rounded-lg\">\r\n <p className=\"text-red-800 text-sm font-medium\">\r\n {error}\r\n </p>\r\n </div>\r\n )}\r\n\r\n <Button\r\n type=\"submit\"\r\n size=\"lg\"\r\n className=\"w-full\"\r\n disabled={isSubmitting}\r\n >\r\n {isSubmitting ? (\r\n <>\r\n <div className=\"w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin mr-2\" />\r\n {t(\"submitting\", \"Creating account...\")}\r\n </>\r\n ) : (\r\n t(\"submit\", \"Create Account\")\r\n )}\r\n </Button>\r\n\r\n <div className=\"text-center text-sm text-muted-foreground\">\r\n {t(\"hasAccount\", \"Already have an account?\")}{\" \"}\r\n <Link\r\n to=\"/login\"\r\n className=\"text-primary hover:underline font-medium\"\r\n >\r\n {t(\"loginLink\", \"Sign in\")}\r\n </Link>\r\n </div>\r\n </form>\r\n </CardContent>\r\n </Card>\r\n </div>\r\n </div>\r\n </div>\r\n </Layout>\r\n );\r\n}\r\n\r\nexport default RegisterPage;\r\n"
27
27
  },
28
28
  {
29
29
  "path": "register-page/lang/en.json",
30
30
  "type": "registry:lang",
31
31
  "target": "$modules$/register-page/lang/en.json",
32
- "content": "{\n \"title\": \"Create Account\",\n \"description\": \"Create an account to get started\",\n \"cardTitle\": \"Sign Up\",\n \"username\": \"Username\",\n \"usernamePlaceholder\": \"Enter your username\",\n \"email\": \"Email\",\n \"emailPlaceholder\": \"Enter your email\",\n \"password\": \"Password\",\n \"passwordPlaceholder\": \"Enter password\",\n \"confirmPassword\": \"Confirm Password\",\n \"confirmPasswordPlaceholder\": \"Confirm your password\",\n \"passwordMismatch\": \"Passwords do not match\",\n \"submit\": \"Create Account\",\n \"submitting\": \"Creating account...\",\n \"hasAccount\": \"Already have an account?\",\n \"loginLink\": \"Sign in\",\n \"toastSuccessTitle\": \"Account created!\",\n \"toastSuccessDesc\": \"Please check your email to verify your account.\",\n \"toastErrorTitle\": \"Registration failed\",\n \"errorGeneric\": \"Registration failed. Please try again.\",\n \"successTitle\": \"Account Created!\",\n \"successMessage\": \"Please check your email to verify your account.\",\n \"goToLogin\": \"Go to Login\"\n}\n"
32
+ "content": "{\r\n \"title\": \"Create Account\",\r\n \"description\": \"Create an account to get started\",\r\n \"cardTitle\": \"Sign Up\",\r\n \"username\": \"Username\",\r\n \"usernamePlaceholder\": \"Enter your username\",\r\n \"email\": \"Email\",\r\n \"emailPlaceholder\": \"Enter your email\",\r\n \"password\": \"Password\",\r\n \"passwordPlaceholder\": \"Enter password\",\r\n \"confirmPassword\": \"Confirm Password\",\r\n \"confirmPasswordPlaceholder\": \"Confirm your password\",\r\n \"passwordMismatch\": \"Passwords do not match\",\r\n \"submit\": \"Create Account\",\r\n \"submitting\": \"Creating account...\",\r\n \"hasAccount\": \"Already have an account?\",\r\n \"loginLink\": \"Sign in\",\r\n \"toastSuccessTitle\": \"Account created!\",\r\n \"toastSuccessDesc\": \"Please check your email to verify your account.\",\r\n \"toastErrorTitle\": \"Registration failed\",\r\n \"errorGeneric\": \"Registration failed. Please try again.\",\r\n \"successTitle\": \"Account Created!\",\r\n \"successMessage\": \"Please check your email to verify your account.\",\r\n \"goToLogin\": \"Go to Login\"\r\n}\r\n"
33
33
  },
34
34
  {
35
35
  "path": "register-page/lang/tr.json",
36
36
  "type": "registry:lang",
37
37
  "target": "$modules$/register-page/lang/tr.json",
38
- "content": "{\n \"title\": \"Hesap Oluştur\",\n \"description\": \"Başlamak için bir hesap oluşturun\",\n \"cardTitle\": \"Kayıt Ol\",\n \"username\": \"Kullanıcı Adı\",\n \"usernamePlaceholder\": \"Kullanıcı adınızı girin\",\n \"email\": \"E-posta\",\n \"emailPlaceholder\": \"E-posta adresinizi girin\",\n \"password\": \"Şifre\",\n \"passwordPlaceholder\": \"Şifre girin\",\n \"confirmPassword\": \"Şifre Onayı\",\n \"confirmPasswordPlaceholder\": \"Şifrenizi onaylayın\",\n \"passwordMismatch\": \"Şifreler eşleşmiyor\",\n \"submit\": \"Hesap Oluştur\",\n \"submitting\": \"Hesap oluşturuluyor...\",\n \"hasAccount\": \"Zaten hesabınız var mı?\",\n \"loginLink\": \"Giriş yap\",\n \"toastSuccessTitle\": \"Hesap oluşturuldu!\",\n \"toastSuccessDesc\": \"Lütfen hesabınızı doğrulamak için e-postanızı kontrol edin.\",\n \"toastErrorTitle\": \"Kayıt başarısız\",\n \"errorGeneric\": \"Kayıt başarısız. Lütfen tekrar deneyin.\",\n \"successTitle\": \"Hesap Oluşturuldu!\",\n \"successMessage\": \"Lütfen hesabınızı doğrulamak için e-postanızı kontrol edin.\",\n \"goToLogin\": \"Girişe Git\"\n}\n"
38
+ "content": "{\r\n \"title\": \"Hesap Oluştur\",\r\n \"description\": \"Başlamak için bir hesap oluşturun\",\r\n \"cardTitle\": \"Kayıt Ol\",\r\n \"username\": \"Kullanıcı Adı\",\r\n \"usernamePlaceholder\": \"Kullanıcı adınızı girin\",\r\n \"email\": \"E-posta\",\r\n \"emailPlaceholder\": \"E-posta adresinizi girin\",\r\n \"password\": \"Şifre\",\r\n \"passwordPlaceholder\": \"Şifre girin\",\r\n \"confirmPassword\": \"Şifre Onayı\",\r\n \"confirmPasswordPlaceholder\": \"Şifrenizi onaylayın\",\r\n \"passwordMismatch\": \"Şifreler eşleşmiyor\",\r\n \"submit\": \"Hesap Oluştur\",\r\n \"submitting\": \"Hesap oluşturuluyor...\",\r\n \"hasAccount\": \"Zaten hesabınız var mı?\",\r\n \"loginLink\": \"Giriş yap\",\r\n \"toastSuccessTitle\": \"Hesap oluşturuldu!\",\r\n \"toastSuccessDesc\": \"Lütfen hesabınızı doğrulamak için e-postanızı kontrol edin.\",\r\n \"toastErrorTitle\": \"Kayıt başarısız\",\r\n \"errorGeneric\": \"Kayıt başarısız. Lütfen tekrar deneyin.\",\r\n \"successTitle\": \"Hesap Oluşturuldu!\",\r\n \"successMessage\": \"Lütfen hesabınızı doğrulamak için e-postanızı kontrol edin.\",\r\n \"goToLogin\": \"Girişe Git\"\r\n}\r\n"
39
39
  }
40
40
  ],
41
41
  "exports": {
@@ -13,7 +13,7 @@
13
13
  "path": "related-posts-block/index.ts",
14
14
  "type": "registry:index",
15
15
  "target": "$modules$/related-posts-block/index.ts",
16
- "content": "export * from './related-posts-block';\n"
16
+ "content": "export * from './related-posts-block';\r\n"
17
17
  },
18
18
  {
19
19
  "path": "related-posts-block/related-posts-block.tsx",
@@ -13,7 +13,7 @@
13
13
  "path": "related-products-block/index.ts",
14
14
  "type": "registry:index",
15
15
  "target": "$modules$/related-products-block/index.ts",
16
- "content": "export * from './related-products-block';\n"
16
+ "content": "export * from './related-products-block';\r\n"
17
17
  },
18
18
  {
19
19
  "path": "related-products-block/related-products-block.tsx",
@@ -17,25 +17,25 @@
17
17
  "path": "reset-password-page-split/index.ts",
18
18
  "type": "registry:index",
19
19
  "target": "$modules$/reset-password-page-split/index.ts",
20
- "content": "export * from './reset-password-page-split';\nexport { default } from './reset-password-page-split';\n"
20
+ "content": "export * from './reset-password-page-split';\r\nexport { default } from './reset-password-page-split';\r\n"
21
21
  },
22
22
  {
23
23
  "path": "reset-password-page-split/reset-password-page-split.tsx",
24
24
  "type": "registry:page",
25
25
  "target": "$modules$/reset-password-page-split/reset-password-page-split.tsx",
26
- "content": "import { useState } from \"react\";\nimport { Link, useNavigate, useSearchParams } from \"react-router\";\nimport { toast } from \"sonner\";\nimport { useTranslation } from \"react-i18next\";\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 { KeyRound, ArrowLeft, CheckCircle } from \"lucide-react\";\nimport { useAuth } from \"@/modules/auth-core\";\nimport { getErrorMessage } from \"@/modules/api\";\n\ninterface ResetPasswordPageSplitProps {\n image?: string;\n}\n\nexport function ResetPasswordPageSplit({\n image = \"/images/placeholder.png\",\n}: ResetPasswordPageSplitProps) {\n const { t } = useTranslation(\"reset-password-page-split\");\n usePageTitle({ title: t(\"title\", \"Reset Password\") });\n const navigate = useNavigate();\n const [searchParams] = useSearchParams();\n const { resetPassword } = useAuth();\n\n // Get code and username from URL params\n const code = searchParams.get(\"code\") || \"\";\n const username = searchParams.get(\"username\") || searchParams.get(\"email\") || \"\";\n\n const [password, setPassword] = useState(\"\");\n const [confirmPassword, setConfirmPassword] = useState(\"\");\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [isSuccess, setIsSuccess] = useState(false);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n\n // Validate passwords match\n if (password !== confirmPassword) {\n setError(t(\"passwordMismatch\", \"Passwords do not match\"));\n return;\n }\n\n // Validate we have required params\n if (!code || !username) {\n setError(t(\"invalidLink\", \"Invalid or expired reset link. Please request a new one.\"));\n return;\n }\n\n setIsLoading(true);\n\n try {\n await resetPassword(username, code, password);\n\n setIsSuccess(true);\n toast.success(t(\"passwordResetSuccess\", \"Password reset successfully!\"));\n } catch (err) {\n const errorMessage = getErrorMessage(\n err,\n t(\"resetPasswordError\", \"Failed to reset password. Please try again.\")\n );\n setError(errorMessage);\n } finally {\n setIsLoading(false);\n }\n };\n\n // Success state\n if (isSuccess) {\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 text-center\">\n <Logo />\n <hr />\n\n <div className=\"flex justify-center\">\n <div className=\"w-16 h-16 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center\">\n <CheckCircle className=\"w-8 h-8 text-green-600 dark:text-green-400\" />\n </div>\n </div>\n\n <div>\n <h1 className=\"text-xl font-bold tracking-tight\">\n {t(\"passwordReset\", \"Password Reset!\")}\n </h1>\n <p className=\"text-sm text-muted-foreground mt-2\">\n {t(\"passwordResetDescription\", \"Your password has been reset successfully. You can now log in with your new password.\")}\n </p>\n </div>\n\n <Button onClick={() => navigate(\"/login\")} className=\"w-full\">\n {t(\"goToLogin\", \"Go to Login\")}\n </Button>\n\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\", \"Reset password 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\n // Invalid link state\n if (!code || !username) {\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 text-center\">\n <Logo />\n <hr />\n\n <div>\n <h1 className=\"text-xl font-bold tracking-tight text-red-600\">\n {t(\"invalidLinkTitle\", \"Invalid Reset Link\")}\n </h1>\n <p className=\"text-sm text-muted-foreground mt-2\">\n {t(\"invalidLinkDescription\", \"This password reset link is invalid or has expired. Please request a new one.\")}\n </p>\n </div>\n\n <Button onClick={() => navigate(\"/forgot-password\")} className=\"w-full\">\n {t(\"requestNewLink\", \"Request New Link\")}\n </Button>\n\n <Link\n to=\"/login\"\n className=\"inline-flex items-center justify-center gap-2 text-sm text-muted-foreground hover:text-foreground\"\n >\n <ArrowLeft className=\"w-4 h-4\" />\n {t(\"backToLogin\", \"Back to login\")}\n </Link>\n\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\", \"Reset password 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\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\n <div className=\"flex justify-center\">\n <div className=\"w-12 h-12 bg-primary/10 rounded-full flex items-center justify-center\">\n <KeyRound className=\"w-6 h-6 text-primary\" />\n </div>\n </div>\n\n <div className=\"text-center\">\n <h1 className=\"text-xl font-bold tracking-tight\">\n {t(\"title\", \"Reset Password\")}\n </h1>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {t(\"subtitle\", \"Enter your new password below\")}\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=\"password\">{t(\"newPassword\", \"New Password\")}</Label>\n <Input\n required\n id=\"password\"\n type=\"password\"\n autoComplete=\"new-password\"\n placeholder=\"••••••••\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n disabled={isLoading}\n minLength={8}\n />\n </div>\n\n <div className=\"grid gap-2\">\n <Label htmlFor=\"confirm-password\">{t(\"confirmPassword\", \"Confirm Password\")}</Label>\n <Input\n required\n id=\"confirm-password\"\n type=\"password\"\n autoComplete=\"new-password\"\n placeholder=\"••••••••\"\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n disabled={isLoading}\n minLength={8}\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(\"resetting\", \"Resetting...\")}\n </>\n ) : (\n t(\"resetPassword\", \"Reset Password\")\n )}\n </Button>\n </form>\n\n <Link\n to=\"/login\"\n className=\"inline-flex items-center justify-center gap-2 text-sm text-muted-foreground hover:text-foreground\"\n >\n <ArrowLeft className=\"w-4 h-4\" />\n {t(\"backToLogin\", \"Back to login\")}\n </Link>\n\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\", \"Reset password 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 ResetPasswordPageSplit;\n"
26
+ "content": "import { useState } from \"react\";\r\nimport { Link, useNavigate, useSearchParams } from \"react-router\";\r\nimport { toast } from \"sonner\";\r\nimport { useTranslation } from \"react-i18next\";\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 { KeyRound, ArrowLeft, CheckCircle } from \"lucide-react\";\r\nimport { useAuth } from \"@/modules/auth-core\";\r\nimport { getErrorMessage } from \"@/modules/api\";\r\n\r\ninterface ResetPasswordPageSplitProps {\r\n image?: string;\r\n}\r\n\r\nexport function ResetPasswordPageSplit({\r\n image = \"/images/placeholder.png\",\r\n}: ResetPasswordPageSplitProps) {\r\n const { t } = useTranslation(\"reset-password-page-split\");\r\n usePageTitle({ title: t(\"title\", \"Reset Password\") });\r\n const navigate = useNavigate();\r\n const [searchParams] = useSearchParams();\r\n const { resetPassword } = useAuth();\r\n\r\n // Get code and username from URL params\r\n const code = searchParams.get(\"code\") || \"\";\r\n const username = searchParams.get(\"username\") || searchParams.get(\"email\") || \"\";\r\n\r\n const [password, setPassword] = useState(\"\");\r\n const [confirmPassword, setConfirmPassword] = useState(\"\");\r\n const [isLoading, setIsLoading] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [isSuccess, setIsSuccess] = useState(false);\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setError(null);\r\n\r\n // Validate passwords match\r\n if (password !== confirmPassword) {\r\n setError(t(\"passwordMismatch\", \"Passwords do not match\"));\r\n return;\r\n }\r\n\r\n // Validate we have required params\r\n if (!code || !username) {\r\n setError(t(\"invalidLink\", \"Invalid or expired reset link. Please request a new one.\"));\r\n return;\r\n }\r\n\r\n setIsLoading(true);\r\n\r\n try {\r\n await resetPassword(username, code, password);\r\n\r\n setIsSuccess(true);\r\n toast.success(t(\"passwordResetSuccess\", \"Password reset successfully!\"));\r\n } catch (err) {\r\n const errorMessage = getErrorMessage(\r\n err,\r\n t(\"resetPasswordError\", \"Failed to reset password. Please try again.\")\r\n );\r\n setError(errorMessage);\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n };\r\n\r\n // Success state\r\n if (isSuccess) {\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 text-center\">\r\n <Logo />\r\n <hr />\r\n\r\n <div className=\"flex justify-center\">\r\n <div className=\"w-16 h-16 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center\">\r\n <CheckCircle className=\"w-8 h-8 text-green-600 dark:text-green-400\" />\r\n </div>\r\n </div>\r\n\r\n <div>\r\n <h1 className=\"text-xl font-bold tracking-tight\">\r\n {t(\"passwordReset\", \"Password Reset!\")}\r\n </h1>\r\n <p className=\"text-sm text-muted-foreground mt-2\">\r\n {t(\"passwordResetDescription\", \"Your password has been reset successfully. You can now log in with your new password.\")}\r\n </p>\r\n </div>\r\n\r\n <Button onClick={() => navigate(\"/login\")} className=\"w-full\">\r\n {t(\"goToLogin\", \"Go to Login\")}\r\n </Button>\r\n\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\", \"Reset password 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\n // Invalid link state\r\n if (!code || !username) {\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 text-center\">\r\n <Logo />\r\n <hr />\r\n\r\n <div>\r\n <h1 className=\"text-xl font-bold tracking-tight text-red-600\">\r\n {t(\"invalidLinkTitle\", \"Invalid Reset Link\")}\r\n </h1>\r\n <p className=\"text-sm text-muted-foreground mt-2\">\r\n {t(\"invalidLinkDescription\", \"This password reset link is invalid or has expired. Please request a new one.\")}\r\n </p>\r\n </div>\r\n\r\n <Button onClick={() => navigate(\"/forgot-password\")} className=\"w-full\">\r\n {t(\"requestNewLink\", \"Request New Link\")}\r\n </Button>\r\n\r\n <Link\r\n to=\"/login\"\r\n className=\"inline-flex items-center justify-center gap-2 text-sm text-muted-foreground hover:text-foreground\"\r\n >\r\n <ArrowLeft className=\"w-4 h-4\" />\r\n {t(\"backToLogin\", \"Back to login\")}\r\n </Link>\r\n\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\", \"Reset password 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\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\r\n <div className=\"flex justify-center\">\r\n <div className=\"w-12 h-12 bg-primary/10 rounded-full flex items-center justify-center\">\r\n <KeyRound className=\"w-6 h-6 text-primary\" />\r\n </div>\r\n </div>\r\n\r\n <div className=\"text-center\">\r\n <h1 className=\"text-xl font-bold tracking-tight\">\r\n {t(\"title\", \"Reset Password\")}\r\n </h1>\r\n <p className=\"text-sm text-muted-foreground mt-1\">\r\n {t(\"subtitle\", \"Enter your new password below\")}\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=\"password\">{t(\"newPassword\", \"New Password\")}</Label>\r\n <Input\r\n required\r\n id=\"password\"\r\n type=\"password\"\r\n autoComplete=\"new-password\"\r\n placeholder=\"••••••••\"\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n disabled={isLoading}\r\n minLength={8}\r\n />\r\n </div>\r\n\r\n <div className=\"grid gap-2\">\r\n <Label htmlFor=\"confirm-password\">{t(\"confirmPassword\", \"Confirm Password\")}</Label>\r\n <Input\r\n required\r\n id=\"confirm-password\"\r\n type=\"password\"\r\n autoComplete=\"new-password\"\r\n placeholder=\"••••••••\"\r\n value={confirmPassword}\r\n onChange={(e) => setConfirmPassword(e.target.value)}\r\n disabled={isLoading}\r\n minLength={8}\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(\"resetting\", \"Resetting...\")}\r\n </>\r\n ) : (\r\n t(\"resetPassword\", \"Reset Password\")\r\n )}\r\n </Button>\r\n </form>\r\n\r\n <Link\r\n to=\"/login\"\r\n className=\"inline-flex items-center justify-center gap-2 text-sm text-muted-foreground hover:text-foreground\"\r\n >\r\n <ArrowLeft className=\"w-4 h-4\" />\r\n {t(\"backToLogin\", \"Back to login\")}\r\n </Link>\r\n\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\", \"Reset password 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 ResetPasswordPageSplit;\r\n"
27
27
  },
28
28
  {
29
29
  "path": "reset-password-page-split/lang/en.json",
30
30
  "type": "registry:lang",
31
31
  "target": "$modules$/reset-password-page-split/lang/en.json",
32
- "content": "{\n \"title\": \"Reset Password\",\n \"subtitle\": \"Enter your new password below\",\n \"newPassword\": \"New Password\",\n \"confirmPassword\": \"Confirm Password\",\n \"resetPassword\": \"Reset Password\",\n \"resetting\": \"Resetting...\",\n \"passwordMismatch\": \"Passwords do not match\",\n \"invalidLink\": \"Invalid or expired reset link. Please request a new one.\",\n \"passwordResetSuccess\": \"Password reset successfully!\",\n \"resetPasswordError\": \"Failed to reset password. Please try again.\",\n \"passwordReset\": \"Password Reset!\",\n \"passwordResetDescription\": \"Your password has been reset successfully. You can now log in with your new password.\",\n \"goToLogin\": \"Go to Login\",\n \"invalidLinkTitle\": \"Invalid Reset Link\",\n \"invalidLinkDescription\": \"This password reset link is invalid or has expired. Please request a new one.\",\n \"requestNewLink\": \"Request New Link\",\n \"backToLogin\": \"Back to login\",\n \"copyright\": \"All rights reserved.\",\n \"imageAlt\": \"Reset password background\"\n}\n"
32
+ "content": "{\r\n \"title\": \"Reset Password\",\r\n \"subtitle\": \"Enter your new password below\",\r\n \"newPassword\": \"New Password\",\r\n \"confirmPassword\": \"Confirm Password\",\r\n \"resetPassword\": \"Reset Password\",\r\n \"resetting\": \"Resetting...\",\r\n \"passwordMismatch\": \"Passwords do not match\",\r\n \"invalidLink\": \"Invalid or expired reset link. Please request a new one.\",\r\n \"passwordResetSuccess\": \"Password reset successfully!\",\r\n \"resetPasswordError\": \"Failed to reset password. Please try again.\",\r\n \"passwordReset\": \"Password Reset!\",\r\n \"passwordResetDescription\": \"Your password has been reset successfully. You can now log in with your new password.\",\r\n \"goToLogin\": \"Go to Login\",\r\n \"invalidLinkTitle\": \"Invalid Reset Link\",\r\n \"invalidLinkDescription\": \"This password reset link is invalid or has expired. Please request a new one.\",\r\n \"requestNewLink\": \"Request New Link\",\r\n \"backToLogin\": \"Back to login\",\r\n \"copyright\": \"All rights reserved.\",\r\n \"imageAlt\": \"Reset password background\"\r\n}\r\n"
33
33
  },
34
34
  {
35
35
  "path": "reset-password-page-split/lang/tr.json",
36
36
  "type": "registry:lang",
37
37
  "target": "$modules$/reset-password-page-split/lang/tr.json",
38
- "content": "{\n \"title\": \"Şifre Sıfırla\",\n \"subtitle\": \"Yeni şifrenizi aşağıya girin\",\n \"newPassword\": \"Yeni Şifre\",\n \"confirmPassword\": \"Şifreyi Onayla\",\n \"resetPassword\": \"Şifreyi Sıfırla\",\n \"resetting\": \"Sıfırlanıyor...\",\n \"passwordMismatch\": \"Şifreler eşleşmiyor\",\n \"invalidLink\": \"Geçersiz veya süresi dolmuş sıfırlama bağlantısı. Lütfen yeni bir tane isteyin.\",\n \"passwordResetSuccess\": \"Şifre başarıyla sıfırlandı!\",\n \"resetPasswordError\": \"Şifre sıfırlanamadı. Lütfen tekrar deneyin.\",\n \"passwordReset\": \"Şifre Sıfırlandı!\",\n \"passwordResetDescription\": \"Şifreniz başarıyla sıfırlandı. Artık yeni şifrenizle giriş yapabilirsiniz.\",\n \"goToLogin\": \"Girişe Git\",\n \"invalidLinkTitle\": \"Geçersiz Sıfırlama Bağlantısı\",\n \"invalidLinkDescription\": \"Bu şifre sıfırlama bağlantısı geçersiz veya süresi dolmuş. Lütfen yeni bir tane isteyin.\",\n \"requestNewLink\": \"Yeni Bağlantı İste\",\n \"backToLogin\": \"Girişe dön\",\n \"copyright\": \"Tüm hakları saklıdır.\",\n \"imageAlt\": \"Şifre sıfırlama arka planı\"\n}\n"
38
+ "content": "{\r\n \"title\": \"Şifre Sıfırla\",\r\n \"subtitle\": \"Yeni şifrenizi aşağıya girin\",\r\n \"newPassword\": \"Yeni Şifre\",\r\n \"confirmPassword\": \"Şifreyi Onayla\",\r\n \"resetPassword\": \"Şifreyi Sıfırla\",\r\n \"resetting\": \"Sıfırlanıyor...\",\r\n \"passwordMismatch\": \"Şifreler eşleşmiyor\",\r\n \"invalidLink\": \"Geçersiz veya süresi dolmuş sıfırlama bağlantısı. Lütfen yeni bir tane isteyin.\",\r\n \"passwordResetSuccess\": \"Şifre başarıyla sıfırlandı!\",\r\n \"resetPasswordError\": \"Şifre sıfırlanamadı. Lütfen tekrar deneyin.\",\r\n \"passwordReset\": \"Şifre Sıfırlandı!\",\r\n \"passwordResetDescription\": \"Şifreniz başarıyla sıfırlandı. Artık yeni şifrenizle giriş yapabilirsiniz.\",\r\n \"goToLogin\": \"Girişe Git\",\r\n \"invalidLinkTitle\": \"Geçersiz Sıfırlama Bağlantısı\",\r\n \"invalidLinkDescription\": \"Bu şifre sıfırlama bağlantısı geçersiz veya süresi dolmuş. Lütfen yeni bir tane isteyin.\",\r\n \"requestNewLink\": \"Yeni Bağlantı İste\",\r\n \"backToLogin\": \"Girişe dön\",\r\n \"copyright\": \"Tüm hakları saklıdır.\",\r\n \"imageAlt\": \"Şifre sıfırlama arka planı\"\r\n}\r\n"
39
39
  }
40
40
  ],
41
41
  "exports": {