@raxonltd/raxon-core 1.1.7 → 1.1.13

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 (89) hide show
  1. package/core/component/general.image.tsx +86 -0
  2. package/core/context/cart.context.tsx +446 -0
  3. package/core/context/security.context.tsx +151 -0
  4. package/core/feature/address/api/places.api.ts +92 -0
  5. package/core/feature/address/form/address-search-input.tsx +125 -0
  6. package/core/feature/address/hook/use.addres.tsx +63 -0
  7. package/core/feature/address/hook/use.address-autocomplete.ts +116 -0
  8. package/core/feature/address/util/address.types.ts +38 -0
  9. package/core/feature/address/util/parse-google-place.ts +66 -0
  10. package/core/feature/analytic-event/analytic.event.api.ts +27 -0
  11. package/core/feature/analytic-event/analytic.event.context.tsx +180 -0
  12. package/core/feature/analytic-event/analytic.event.util.ts +42 -0
  13. package/core/feature/analytic-event/use.analytic.auto.tsx +114 -0
  14. package/core/feature/article/hook/use.article.tsx +33 -0
  15. package/core/feature/attribute/hook/use.attribute.tsx +24 -0
  16. package/core/feature/auth/hook/use.auth.tsx +141 -0
  17. package/core/feature/auth/modal/modal.auth.tsx +80 -0
  18. package/core/feature/auth/view/view.login.tsx +199 -0
  19. package/core/feature/auth/view/view.register.tsx +333 -0
  20. package/core/feature/bank-account/hook/use.bank.account.tsx +47 -0
  21. package/core/feature/brand/hook/use.brand.tsx +24 -0
  22. package/core/feature/cart/component/cart.order.summary.tsx +89 -0
  23. package/core/feature/cart/component/cart.promo.code.section.tsx +208 -0
  24. package/core/feature/cart/hook/use.cart.tsx +267 -0
  25. package/core/feature/cart/util/basket-pay.response.ts +67 -0
  26. package/core/feature/cart/util/cart-optimistic.ts +425 -0
  27. package/core/feature/cart/util/garanti-payment.ts +27 -0
  28. package/core/feature/collection/hook/use.collection.tsx +32 -0
  29. package/core/feature/delivery-method/hook/use.delivery.method.tsx +40 -0
  30. package/core/feature/delivery-method/util/checkout.delivery.method.ts +11 -0
  31. package/core/feature/faq/hook/use.faq.tsx +23 -0
  32. package/core/feature/favorite/hook/use.favorite.tsx +48 -0
  33. package/core/feature/form-submit/form/form.contact.tsx +118 -0
  34. package/core/feature/form-submit/hook/use.form.submit.tsx +16 -0
  35. package/core/feature/invoice/hook/use.invoice.tsx +51 -0
  36. package/core/feature/newsletter/hook/use.newsletter.tsx +124 -0
  37. package/core/feature/newsletter/modal/modal.newsletter.product.tsx +163 -0
  38. package/core/feature/order/hook/use.order.tsx +31 -0
  39. package/core/feature/payment-method/checkout.payment.options.ts +117 -0
  40. package/core/feature/payment-method/hook/use.payment.method.tsx +44 -0
  41. package/core/feature/product/hook/use.product.tsx +122 -0
  42. package/core/feature/profile/hook/use.profile.tsx +126 -0
  43. package/core/feature/promo-code/hook/use.promo.code.tsx +27 -0
  44. package/core/interface/basket.interface.ts +360 -0
  45. package/core/interface/bootstrap.interface.ts +39 -0
  46. package/core/interface/context.interface.ts +9 -0
  47. package/core/interface/inventory.interface.ts +88 -0
  48. package/core/interface/nexine.interface.ts +4 -0
  49. package/core/interface/prisma.interface.ts +8844 -0
  50. package/core/interface/product.interface.ts +111 -0
  51. package/core/raxon.context.tsx +256 -0
  52. package/core/schema/checkout.schema.ts +103 -0
  53. package/core/server/places.proxy.ts +35 -0
  54. package/core/server/raxon.bootstrap.route.ts +39 -0
  55. package/core/server/raxon.server.ts +80 -0
  56. package/core/util/basket.item.display.ts +19 -0
  57. package/core/util/category.nav.ts +46 -0
  58. package/core/util/client-ip.ts +35 -0
  59. package/core/util/collection.util.ts +433 -0
  60. package/core/util/fetch.bootstrap.ts +21 -0
  61. package/core/util/garanti-payment.ts +5 -0
  62. package/core/util/nexine.axios.tsx +104 -0
  63. package/core/util/no-cache.ts +6 -0
  64. package/core/util/util.ts +191 -0
  65. package/core/view/view.checkout.tsx +1964 -0
  66. package/dist/core/feature/address/api/places.api.d.ts.map +1 -1
  67. package/dist/core/feature/address/api/places.api.js +18 -4
  68. package/dist/core/server/places.proxy.d.ts +10 -0
  69. package/dist/core/server/places.proxy.d.ts.map +1 -0
  70. package/dist/core/server/places.proxy.js +24 -0
  71. package/dist/core/server/raxon.bootstrap.route.d.ts +7 -0
  72. package/dist/core/server/raxon.bootstrap.route.d.ts.map +1 -0
  73. package/dist/core/server/raxon.bootstrap.route.js +27 -0
  74. package/dist/core/server/raxon.server.d.ts +24 -0
  75. package/dist/core/server/raxon.server.d.ts.map +1 -0
  76. package/dist/core/server/raxon.server.js +59 -0
  77. package/dist/core/view/view.checkout.js +2 -2
  78. package/dist/middleware.d.ts +6 -0
  79. package/dist/middleware.d.ts.map +1 -0
  80. package/dist/middleware.js +5 -0
  81. package/dist/server-bootstrap.d.ts +2 -0
  82. package/dist/server-bootstrap.d.ts.map +1 -0
  83. package/dist/server-bootstrap.js +1 -0
  84. package/dist/server.d.ts +3 -0
  85. package/dist/server.d.ts.map +1 -0
  86. package/dist/server.js +1 -0
  87. package/dist/tsconfig.tsbuildinfo +1 -1
  88. package/package.json +22 -3
  89. package/tailwind.css +11 -0
@@ -0,0 +1,199 @@
1
+ 'use client';
2
+ import React, { useState } from 'react';
3
+ import { Eye, EyeOff, Lock, Mail, ArrowRight } from 'lucide-react';
4
+ import Link from 'next/link';
5
+ import { useAuth } from '@/core/feature/auth/hook/use.auth';
6
+ import { useForm } from 'react-hook-form';
7
+ import { useRouter } from 'next/navigation';
8
+ import toast from 'react-hot-toast';
9
+
10
+ interface ViewLoginProps {
11
+ onClose?: () => void;
12
+ returnUrl?: string;
13
+ }
14
+
15
+ export default function ViewLogin({ onClose, returnUrl }: ViewLoginProps) {
16
+ const [showPassword, setShowPassword] = useState(false);
17
+ const { mutate: login } = useAuth().loginEmail();
18
+ const { mutate: loginGuest } = useAuth().loginGuest();
19
+ const { mutate: loginSocial } = useAuth().loginSocial();
20
+ const form = useForm();
21
+
22
+
23
+ const handleSubmitGuest = (e: React.FormEvent) => {
24
+ e.preventDefault();
25
+ loginGuest({} as any, {
26
+ onSuccess: () => {
27
+ onClose?.();
28
+ },
29
+ });
30
+ };
31
+
32
+ const handleLoginSocial = (provider: string) => {
33
+ loginSocial({ platform: provider, returnUrl: returnUrl }, {
34
+ onSuccess: (url) => {
35
+ if (typeof window !== 'undefined') {
36
+ window.location.href = url;
37
+ }
38
+
39
+
40
+
41
+ },
42
+ });
43
+ };
44
+
45
+ const handleSubmit = (e: React.FormEvent) => {
46
+ e.preventDefault();
47
+ form.handleSubmit(data => {
48
+ login(data, {
49
+ onSuccess: () => {
50
+
51
+ onClose?.();
52
+
53
+ },
54
+ onError: (error: any) => {
55
+ toast.error(error?.response?.data?.info?.title || 'Giriş başarısız');
56
+ }
57
+ });
58
+ })();
59
+ };
60
+
61
+ return (
62
+ <form onSubmit={handleSubmit} className="space-y-6">
63
+ {/* Email Field */}
64
+ <div>
65
+ <input
66
+ type="email"
67
+ {...form.register('email')}
68
+ placeholder="E-posta adresinizi girin *"
69
+ className="w-full px-0 py-5 text-lg font-medium border-0 border-b-2 border-gray-300 bg-transparent focus:outline-none focus:border-black transition-colors placeholder-gray-500"
70
+ required
71
+ />
72
+ </div>
73
+
74
+ {/* Password Field */}
75
+ <div className="relative">
76
+ <input
77
+ type={showPassword ? 'text' : 'password'}
78
+ {...form.register('password')}
79
+ placeholder="Şifre *"
80
+ className="w-full px-0 py-5 pr-10 text-lg font-medium border-0 border-b-2 border-gray-300 bg-transparent focus:outline-none focus:border-black transition-colors placeholder-gray-500"
81
+ required
82
+ />
83
+ <button
84
+ type="button"
85
+ className="absolute right-0 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
86
+ onClick={() => setShowPassword(!showPassword)}
87
+ >
88
+ {showPassword ? <EyeOff className="w-5 h-5" /> : <Eye className="w-5 h-5" />}
89
+ </button>
90
+ </div>
91
+
92
+ {/* Remember Me & Forgot Password */}
93
+ <div className="flex items-center justify-between py-4">
94
+ <div className="flex items-center">
95
+ <input
96
+ id="remember"
97
+ type="checkbox"
98
+ {...form.register('rememberMe')}
99
+ className="w-4 h-4 text-black border-gray-300 rounded focus:ring-0"
100
+ />
101
+ <label htmlFor="remember" className="ml-2 text-base font-medium text-gray-700">Beni hatırla</label>
102
+ </div>
103
+ <button
104
+ type="button"
105
+ onClick={onClose}
106
+ className="text-base font-medium text-gray-600 hover:text-black transition-colors"
107
+ >
108
+ Şifrenizi mi unuttunuz?
109
+ </button>
110
+ </div>
111
+
112
+
113
+
114
+ {/* Social Login */}
115
+ <div className="py-6">
116
+ <div className="flex items-center mb-6">
117
+ <div className="flex-1 border-t border-gray-200"></div>
118
+ <span className="px-4 text-base font-medium text-gray-500">Veya sosyal hesapla devam edin</span>
119
+ <div className="flex-1 border-t border-gray-200"></div>
120
+ </div>
121
+
122
+ <div className="flex flex-col sm:grid sm:grid-cols-2 gap-4">
123
+ <button
124
+ type="button"
125
+ onClick={() => handleLoginSocial('google')}
126
+ className="py-4 text-base font-medium border border-gray-200 hover:border-black transition-colors flex items-center justify-center space-x-2"
127
+ >
128
+ <svg width="20" height="20" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
129
+ <g clipPath="url(#clip0_278_6045)">
130
+ <path d="M21.6696 9.08832L12.696 9.08789C12.2997 9.08789 11.9785 9.40904 11.9785 9.8053V12.672C11.9785 13.0681 12.2997 13.3894 12.6959 13.3894H17.7493C17.196 14.8254 16.1632 16.0281 14.8455 16.7922L17.0002 20.5223C20.4567 18.5233 22.5002 15.0158 22.5002 11.0894C22.5002 10.5303 22.459 10.1307 22.3766 9.68064C22.314 9.33874 22.0171 9.08832 21.6696 9.08832Z" fill="#167EE6"/>
131
+ <path d="M11.4999 17.6964C9.02689 17.6964 6.86797 16.3452 5.70846 14.3457L1.97852 16.4956C3.87666 19.7854 7.4325 22.0007 11.4999 22.0007C13.4953 22.0007 15.378 21.4635 16.9999 20.5272V20.5221L14.8452 16.792C13.8595 17.3637 12.719 17.6964 11.4999 17.6964Z" fill="#12B347"/>
132
+ <path d="M17 20.5262V20.5211L14.8452 16.791C13.8596 17.3626 12.7192 17.6954 11.5 17.6954V21.9997C13.4953 21.9997 15.3782 21.4625 17 20.5262Z" fill="#0F993E"/>
133
+ <path d="M4.80435 11.0007C4.80435 9.78177 5.13702 8.64133 5.70854 7.65576L1.9786 5.50586C1.0372 7.12264 0.5 9.00029 0.5 11.0007C0.5 13.0012 1.0372 14.8788 1.9786 16.4956L5.70854 14.3457C5.13702 13.3602 4.80435 12.2197 4.80435 11.0007Z" fill="#FFD500"/>
134
+ <path d="M11.4999 4.30435C13.1126 4.30435 14.5939 4.87738 15.7509 5.83056C16.0363 6.06568 16.4512 6.04871 16.7127 5.78725L18.7438 3.75611C19.0405 3.45946 19.0193 2.97387 18.7024 2.69895C16.7639 1.0172 14.2416 0 11.4999 0C7.4325 0 3.87666 2.21534 1.97852 5.50511L5.70846 7.65501C6.86797 5.65555 9.02689 4.30435 11.4999 4.30435Z" fill="#FF4B26"/>
135
+ <path d="M15.751 5.83056C16.0364 6.06568 16.4513 6.04871 16.7128 5.78725L18.7439 3.75611C19.0405 3.45946 19.0194 2.97387 18.7025 2.69895C16.764 1.01716 14.2417 0 11.5 0V4.30435C13.1126 4.30435 14.594 4.87738 15.751 5.83056Z" fill="#D93F21"/>
136
+ </g>
137
+ </svg>
138
+ <span className="text-sm sm:text-base">Google ile giriş yap</span>
139
+ </button>
140
+
141
+ <button
142
+ type="button"
143
+ onClick={() => handleLoginSocial('facebook')}
144
+ className="py-4 text-base font-medium border border-gray-200 hover:border-black transition-colors flex items-center justify-center space-x-2"
145
+ >
146
+ <svg width="20" height="20" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
147
+ <g clipPath="url(#clip0_278_6055)">
148
+ <path d="M22.5 11C22.5 16.4905 18.4773 21.0414 13.2188 21.8664V14.1797H15.7818L16.2695 11H13.2188V8.93664C13.2188 8.06652 13.645 7.21875 15.0114 7.21875H16.3984V4.51172C16.3984 4.51172 15.1395 4.29688 13.9359 4.29688C11.4235 4.29688 9.78125 5.81969 9.78125 8.57656V11H6.98828V14.1797H9.78125V21.8664C4.52273 21.0414 0.5 16.4905 0.5 11C0.5 4.92508 5.42508 0 11.5 0C17.5749 0 22.5 4.92508 22.5 11Z" fill="#1877F2"/>
149
+ <path d="M15.7818 14.1797L16.2695 11H13.2188V8.9366C13.2188 8.0667 13.6449 7.21875 15.0114 7.21875H16.3984V4.51172C16.3984 4.51172 15.1396 4.29688 13.9361 4.29688C11.4235 4.29688 9.78125 5.81969 9.78125 8.57656V11H6.98828V14.1797H9.78125V21.8663C10.3413 21.9542 10.9153 22 11.5 22C12.0847 22 12.6587 21.9542 13.2188 21.8663V14.1797H15.7818Z" fill="white"/>
150
+ </g>
151
+ </svg>
152
+ <span className="text-sm sm:text-base">Facebook ile giriş yap</span>
153
+ </button>
154
+ </div>
155
+ </div>
156
+
157
+ {/* Misafir Login */}
158
+ <button
159
+ onClick={handleSubmitGuest}
160
+ type="button"
161
+ className="w-full py-4 text-base font-medium hover:text-black transition-colors"
162
+ >
163
+ Misafir Olarak Devam Et
164
+ </button>
165
+
166
+ {/* Login Button */}
167
+ <button
168
+ id="btnLogin"
169
+ type="submit"
170
+ className="w-full py-5 text-lg font-bold bg-black text-white hover:bg-gray-800 transition-colors"
171
+ >
172
+ Giriş Yap
173
+ </button>
174
+
175
+ {/* Terms */}
176
+ <div className="text-center">
177
+ <p className="text-sm font-medium text-gray-500 leading-relaxed">
178
+ Devam ederek{' '}
179
+ <button
180
+ type="button"
181
+ onClick={onClose}
182
+ className="hover:underline"
183
+ >
184
+ Kullanım Şartları
185
+ </button>{' '}
186
+ ve{' '}
187
+ <button
188
+ type="button"
189
+ onClick={onClose}
190
+ className="hover:underline"
191
+ >
192
+ Gizlilik Politikası
193
+ </button>
194
+ 'nı kabul etmiş olursunuz.
195
+ </p>
196
+ </div>
197
+ </form>
198
+ );
199
+ }
@@ -0,0 +1,333 @@
1
+ 'use client';
2
+ import React, { useState } from 'react';
3
+ import { Eye, EyeOff, Lock, Mail, User, Phone, ArrowRight } from 'lucide-react';
4
+ import { useAuth } from '@/core/feature/auth/hook/use.auth';
5
+ import { useRouter } from 'next/navigation';
6
+ import { useForm } from 'react-hook-form';
7
+ import { zodResolver } from '@hookform/resolvers/zod';
8
+ import { z } from 'zod';
9
+ import toast from 'react-hot-toast';
10
+
11
+ // Türk telefon numarası regex'i - 0 ile başlayan 11 haneli veya 5 ile başlayan 10 haneli
12
+ const turkishPhoneRegex = /^(\+90[5-9][0-9]{9}|0[5-9][0-9]{9}|[5-9][0-9]{8})$/;
13
+
14
+ // Zod validation şeması
15
+ const registerSchema = z.object({
16
+ firstName: z.string()
17
+ .min(1, 'Ad alanı zorunludur')
18
+ .min(2, 'Ad en az 2 karakter olmalıdır')
19
+ .max(50, 'Ad en fazla 50 karakter olabilir')
20
+ .regex(/^[a-zA-ZçğıöşüÇĞIİÖŞÜ\s]+$/, 'Ad sadece harf içerebilir'),
21
+
22
+ lastName: z.string()
23
+ .min(1, 'Soyad alanı zorunludur')
24
+ .min(2, 'Soyad en az 2 karakter olmalıdır')
25
+ .max(50, 'Soyad en fazla 50 karakter olabilir')
26
+ .regex(/^[a-zA-ZçğıöşüÇĞIİÖŞÜ\s]+$/, 'Soyad sadece harf içerebilir'),
27
+
28
+ email: z.string()
29
+ .min(1, 'E-posta alanı zorunludur')
30
+ .email('Geçerli bir e-posta adresi giriniz')
31
+ .max(100, 'E-posta adresi çok uzun'),
32
+
33
+ phone: z.string()
34
+ .min(1, 'Telefon numarası zorunludur')
35
+ .regex(turkishPhoneRegex, 'Geçerli bir Türk telefon numarası giriniz (örn: +905551234567)')
36
+ .transform((val) => val.replace(/\s/g, '')), // Boşlukları temizle
37
+
38
+ password: z.string()
39
+ .min(1, 'Şifre alanı zorunludur')
40
+ .min(6, 'Şifre en az 6 karakter olmalıdır')
41
+ .max(100, 'Şifre çok uzun'),
42
+
43
+ confirmPassword: z.string()
44
+ .min(1, 'Şifre tekrarı zorunludur'),
45
+
46
+ acceptTerms: z.boolean()
47
+ .refine((val) => val === true, 'Kullanım şartlarını kabul etmelisiniz'),
48
+
49
+ acceptMarketing: z.boolean().optional()
50
+ }).refine((data) => data.password === data.confirmPassword, {
51
+ message: 'Şifreler eşleşmiyor',
52
+ path: ['confirmPassword']
53
+ });
54
+
55
+ type RegisterFormData = z.infer<typeof registerSchema>;
56
+
57
+ interface ViewRegisterProps {
58
+ onClose?: () => void;
59
+ onSwitchToLogin?: () => void;
60
+ }
61
+
62
+ export default function ViewRegister({ onClose, onSwitchToLogin }: ViewRegisterProps) {
63
+ const router = useRouter();
64
+ const { register: authRegister } = useAuth();
65
+ const registerMutation = authRegister();
66
+
67
+ const [showPassword, setShowPassword] = useState(false);
68
+ const [showConfirmPassword, setShowConfirmPassword] = useState(false);
69
+
70
+ const {
71
+ register,
72
+ handleSubmit,
73
+ formState: { errors, isSubmitting },
74
+ } = useForm<RegisterFormData>({
75
+ resolver: zodResolver(registerSchema),
76
+ defaultValues: {
77
+ firstName: '',
78
+ lastName: '',
79
+ email: '',
80
+ phone: '',
81
+ password: '',
82
+ confirmPassword: '',
83
+ acceptTerms: false,
84
+ acceptMarketing: false
85
+ }
86
+ });
87
+
88
+ const onSubmit = async (data: RegisterFormData) => {
89
+ registerMutation.mutate({
90
+ firstName: data.firstName,
91
+ lastName: data.lastName,
92
+ email: data.email,
93
+ phone: data.phone,
94
+ password: data.password,
95
+ acceptMarketing: data.acceptMarketing || false
96
+ }, {
97
+ onSuccess: () => {
98
+
99
+ onSwitchToLogin?.();
100
+ },
101
+ onError: (e: any) => {
102
+ toast.error(e.response?.data?.info?.title || 'Kayıt başarısız');
103
+ }
104
+ });
105
+ };
106
+
107
+ return (
108
+ <form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
109
+ {/* Name Fields */}
110
+ <div className="grid grid-cols-2 gap-4">
111
+ <div className="relative">
112
+ <div className="relative">
113
+ <User className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
114
+ <input
115
+ type="text"
116
+ {...register('firstName')}
117
+ placeholder="Adınız"
118
+ className={`w-full pl-10 pr-4 py-3 text-sm border rounded-sm focus:outline-none transition-colors ${
119
+ errors.firstName ? 'border-red-500' : 'border-gray-200 focus:border-black'
120
+ }`}
121
+ />
122
+ </div>
123
+ {errors.firstName && (
124
+ <p className="mt-1 text-xs text-red-500">{errors.firstName.message}</p>
125
+ )}
126
+ </div>
127
+
128
+ <div className="relative">
129
+ <div className="relative">
130
+ <User className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
131
+ <input
132
+ type="text"
133
+ {...register('lastName')}
134
+ placeholder="Soyadınız"
135
+ className={`w-full pl-10 pr-4 py-3 text-sm border rounded-sm focus:outline-none transition-colors ${
136
+ errors.lastName ? 'border-red-500' : 'border-gray-200 focus:border-black'
137
+ }`}
138
+ />
139
+ </div>
140
+ {errors.lastName && (
141
+ <p className="mt-1 text-xs text-red-500">{errors.lastName.message}</p>
142
+ )}
143
+ </div>
144
+ </div>
145
+
146
+ {/* Email Field */}
147
+ <div className="relative">
148
+ <div className="relative">
149
+ <Mail className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
150
+ <input
151
+ type="email"
152
+ {...register('email')}
153
+ placeholder="E-posta adresiniz"
154
+ className={`w-full pl-10 pr-4 py-3 text-sm border rounded-sm focus:outline-none transition-colors ${
155
+ errors.email ? 'border-red-500' : 'border-gray-200 focus:border-black'
156
+ }`}
157
+ />
158
+ </div>
159
+ {errors.email && (
160
+ <p className="mt-1 text-xs text-red-500">{errors.email.message}</p>
161
+ )}
162
+ </div>
163
+
164
+ {/* Phone Field */}
165
+ <div className="relative">
166
+ <div className="relative">
167
+ <Phone className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
168
+ <input
169
+ type="tel"
170
+ {...register('phone')}
171
+ placeholder="Telefon numaranız (örn: 05551234567)"
172
+ className={`w-full pl-10 pr-4 py-3 text-sm border rounded-sm focus:outline-none transition-colors ${
173
+ errors.phone ? 'border-red-500' : 'border-gray-200 focus:border-black'
174
+ }`}
175
+ />
176
+ </div>
177
+ {errors.phone && (
178
+ <p className="mt-1 text-xs text-red-500">{errors.phone.message}</p>
179
+ )}
180
+ </div>
181
+
182
+ {/* Password Field */}
183
+ <div className="relative">
184
+ <div className="relative">
185
+ <Lock className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
186
+ <input
187
+ type={showPassword ? "text" : "password"}
188
+ {...register('password')}
189
+ placeholder="Şifreniz (en az 6 karakter, büyük/küçük harf ve rakam)"
190
+ className={`w-full pl-10 pr-12 py-3 text-sm border rounded-sm focus:outline-none transition-colors ${
191
+ errors.password ? 'border-red-500' : 'border-gray-200 focus:border-black'
192
+ }`}
193
+ />
194
+ <button
195
+ type="button"
196
+ onClick={() => setShowPassword(!showPassword)}
197
+ className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600 transition-colors"
198
+ >
199
+ {showPassword ? (
200
+ <EyeOff className="w-4 h-4" />
201
+ ) : (
202
+ <Eye className="w-4 h-4" />
203
+ )}
204
+ </button>
205
+ </div>
206
+ {errors.password && (
207
+ <p className="mt-1 text-xs text-red-500">{errors.password.message}</p>
208
+ )}
209
+ </div>
210
+
211
+ {/* Confirm Password Field */}
212
+ <div className="relative">
213
+ <div className="relative">
214
+ <Lock className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
215
+ <input
216
+ type={showConfirmPassword ? "text" : "password"}
217
+ {...register('confirmPassword')}
218
+ placeholder="Şifrenizi tekrar giriniz"
219
+ className={`w-full pl-10 pr-12 py-3 text-sm border rounded-sm focus:outline-none transition-colors ${
220
+ errors.confirmPassword ? 'border-red-500' : 'border-gray-200 focus:border-black'
221
+ }`}
222
+ />
223
+ <button
224
+ type="button"
225
+ onClick={() => setShowConfirmPassword(!showConfirmPassword)}
226
+ className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600 transition-colors"
227
+ >
228
+ {showConfirmPassword ? (
229
+ <EyeOff className="w-4 h-4" />
230
+ ) : (
231
+ <Eye className="w-4 h-4" />
232
+ )}
233
+ </button>
234
+ </div>
235
+ {errors.confirmPassword && (
236
+ <p className="mt-1 text-xs text-red-500">{errors.confirmPassword.message}</p>
237
+ )}
238
+ </div>
239
+
240
+ {/* Terms & Marketing Checkboxes */}
241
+ <div className="space-y-3">
242
+ <div className="flex items-start">
243
+ <input
244
+ type="checkbox"
245
+ {...register('acceptTerms')}
246
+ className="w-4 h-4 text-black border-gray-300 rounded focus:ring-0 focus:ring-offset-0 mt-0.5"
247
+ />
248
+ <label className="ml-2 text-sm text-gray-600 font-light">
249
+ <button
250
+ type="button"
251
+ onClick={onClose}
252
+ className="text-black hover:underline"
253
+ >
254
+ Kullanım Şartları
255
+ </button>
256
+ {' '}ve{' '}
257
+ <button
258
+ type="button"
259
+ onClick={onClose}
260
+ className="text-black hover:underline"
261
+ >
262
+ Gizlilik Politikası
263
+ </button>
264
+ 'nı okudum ve kabul ediyorum. *
265
+ </label>
266
+ </div>
267
+ {errors.acceptTerms && (
268
+ <p className="text-xs text-red-500 ml-6">{errors.acceptTerms.message}</p>
269
+ )}
270
+
271
+ <div className="flex items-start">
272
+ <input
273
+ type="checkbox"
274
+ {...register('acceptMarketing')}
275
+ className="w-4 h-4 text-black border-gray-300 rounded focus:ring-0 focus:ring-offset-0 mt-0.5"
276
+ />
277
+ <label className="ml-2 text-sm text-gray-600 font-light">
278
+ Kampanya ve promosyon bilgilerini e-posta ile almak istiyorum.
279
+ </label>
280
+ </div>
281
+ </div>
282
+
283
+ {/* Register Button */}
284
+ <button
285
+ type="submit"
286
+ disabled={isSubmitting || registerMutation.isPending}
287
+ className="w-full bg-black text-white py-3 rounded-sm hover:bg-gray-800 transition-colors duration-200 flex items-center justify-center space-x-2 group disabled:opacity-50 disabled:cursor-not-allowed"
288
+ >
289
+ <span className="text-sm font-light uppercase tracking-wider">
290
+ {isSubmitting || registerMutation.isPending ? 'Kayıt Oluşturuluyor...' : 'Kayıt Ol'}
291
+ </span>
292
+ {!isSubmitting && !registerMutation.isPending && (
293
+ <ArrowRight className="w-4 h-4 group-hover:translate-x-1 transition-transform" />
294
+ )}
295
+ </button>
296
+
297
+ {/* Divider */}
298
+ <div className="my-8 flex items-center">
299
+ <div className="flex-1 border-t border-gray-200"></div>
300
+ <span className="px-4 text-xs text-gray-500 uppercase tracking-wider">
301
+ veya
302
+ </span>
303
+ <div className="flex-1 border-t border-gray-200"></div>
304
+ </div>
305
+
306
+ {/* Social Register */}
307
+ <div className="space-y-3 hidden">
308
+ <button
309
+ type="button"
310
+ className="w-full border border-gray-200 py-3 rounded-sm hover:bg-gray-50 transition-colors duration-200 flex items-center justify-center space-x-2"
311
+ >
312
+ <svg className="w-5 h-5" viewBox="0 0 24 24">
313
+ <path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
314
+ <path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
315
+ <path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
316
+ <path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
317
+ </svg>
318
+ <span className="text-sm font-light">Google ile kayıt ol</span>
319
+ </button>
320
+
321
+ <button
322
+ type="button"
323
+ className="w-full border border-gray-200 py-3 rounded-sm hover:bg-gray-50 transition-colors duration-200 flex items-center justify-center space-x-2"
324
+ >
325
+ <svg className="w-5 h-5 text-blue-600" fill="currentColor" viewBox="0 0 24 24">
326
+ <path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/>
327
+ </svg>
328
+ <span className="text-sm font-light">Facebook ile kayıt ol</span>
329
+ </button>
330
+ </div>
331
+ </form>
332
+ );
333
+ }
@@ -0,0 +1,47 @@
1
+ import { nexineAxios } from '@/core/util/nexine.axios';
2
+ import { IData } from '@/core/interface/nexine.interface';
3
+ import { BankAccount, BankTransferCode } from '@/core/interface/prisma.interface';
4
+ import { useMutation, useQuery } from '@tanstack/react-query';
5
+
6
+ async function fetchBankAccounts() {
7
+ const withTags = await nexineAxios.get<IData<BankAccount>>('/customer/bank-account', {
8
+ params: {
9
+ isCompanySpecificVisible: true,
10
+ tags: ['WEB'],
11
+ },
12
+ });
13
+
14
+ const tagged = withTags.data?.data ?? [];
15
+ if (tagged.length > 0) return withTags.data;
16
+
17
+ const fallback = await nexineAxios.get<IData<BankAccount>>('/customer/bank-account', {
18
+ params: {
19
+ isCompanySpecificVisible: true,
20
+ },
21
+ });
22
+
23
+ return fallback.data;
24
+ }
25
+
26
+ export const useBankAccount = () => {
27
+ return {
28
+ fetch: (opts?: { enabled?: boolean }) => {
29
+ return useQuery({
30
+ queryKey: ['bank-account', 'web'],
31
+ queryFn: fetchBankAccounts,
32
+ enabled: opts?.enabled !== false,
33
+ });
34
+ },
35
+ createTransferCode: () => {
36
+ return useMutation({
37
+ mutationFn: async (data: { amount: number; bankAccountId: string }) => {
38
+ const response = await nexineAxios.post<{ bankTransferCode: BankTransferCode }>(
39
+ '/customer/payment/bank-transfer',
40
+ data
41
+ );
42
+ return response.data.bankTransferCode;
43
+ },
44
+ });
45
+ },
46
+ };
47
+ };
@@ -0,0 +1,24 @@
1
+ import { nexineAxios } from '@/core/util/nexine.axios';
2
+ import { IData } from '@/core/interface/nexine.interface';
3
+ import { Brand } from '@/core/interface/prisma.interface';
4
+ import { useQuery } from '@tanstack/react-query';
5
+
6
+ export const useBrand = () => {
7
+ return {
8
+ fetch: (params?: { enabled?: boolean; page?: number; amount?: number }) => {
9
+ return useQuery({
10
+ queryKey: ['brand', params?.page, params?.amount],
11
+ enabled: params?.enabled ?? true,
12
+ queryFn: async () => {
13
+ const response = await nexineAxios.get<IData<Brand>>('/customer/brand', {
14
+ params: {
15
+ page: params?.page,
16
+ amount: params?.amount,
17
+ },
18
+ });
19
+ return response.data;
20
+ },
21
+ });
22
+ },
23
+ };
24
+ };