@akinon/projectzero 2.0.0-beta.19 → 2.0.0-beta.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -7
- package/app-template/CHANGELOG.md +251 -204
- package/app-template/akinon.json +1 -1
- package/app-template/package.json +28 -28
- package/app-template/public/amex.svg +12 -0
- package/app-template/public/apple-pay.svg +16 -0
- package/app-template/public/assets/images/product-placeholder-1.jpg +0 -0
- package/app-template/public/assets/images/product-placeholder-2.jpg +0 -0
- package/app-template/public/assets/images/product-placeholder-3.jpg +0 -0
- package/app-template/public/assets/images/product-placeholder-4.jpg +0 -0
- package/app-template/public/google-pay.svg +16 -0
- package/app-template/public/locales/en/account.json +6 -3
- package/app-template/public/locales/en/auth.json +6 -7
- package/app-template/public/locales/en/basket.json +6 -6
- package/app-template/public/locales/en/blog.json +7 -0
- package/app-template/public/locales/en/category.json +3 -1
- package/app-template/public/locales/en/checkout.json +5 -4
- package/app-template/public/locales/en/common.json +11 -2
- package/app-template/public/locales/en/forgot_password.json +6 -7
- package/app-template/public/locales/en/product.json +4 -3
- package/app-template/public/locales/tr/account.json +6 -3
- package/app-template/public/locales/tr/auth.json +16 -17
- package/app-template/public/locales/tr/basket.json +4 -4
- package/app-template/public/locales/tr/blog.json +7 -0
- package/app-template/public/locales/tr/category.json +3 -1
- package/app-template/public/locales/tr/checkout.json +39 -38
- package/app-template/public/locales/tr/common.json +10 -1
- package/app-template/public/locales/tr/forgot_password.json +12 -13
- package/app-template/public/locales/tr/product.json +1 -0
- package/app-template/public/logo.svg +3 -27
- package/app-template/public/mastercard.svg +14 -0
- package/app-template/public/promotion-banner.jpg +0 -0
- package/app-template/public/shop-pay.svg +12 -0
- package/app-template/public/visa.svg +12 -0
- package/app-template/src/app/[commerce]/[locale]/[currency]/blog/[slug]/page.tsx +118 -0
- package/app-template/src/app/[commerce]/[locale]/[currency]/pages/[slug]/page.tsx +15 -0
- package/app-template/src/app/api/theme-settings/route.ts +12 -0
- package/app-template/src/assets/fonts/pz-icon.css +211 -49
- package/app-template/src/assets/fonts/pz-icon.eot +0 -0
- package/app-template/src/assets/fonts/pz-icon.html +486 -0
- package/app-template/src/assets/fonts/pz-icon.scss +373 -49
- package/app-template/src/assets/fonts/pz-icon.svg +215 -53
- package/app-template/src/assets/fonts/pz-icon.ttf +0 -0
- package/app-template/src/assets/fonts/pz-icon.woff +0 -0
- package/app-template/src/assets/fonts/pz-icon.woff2 +0 -0
- package/app-template/src/assets/globals.scss +4 -0
- package/app-template/src/assets/icons/arrow-right.svg +3 -0
- package/app-template/src/assets/icons/cart.svg +4 -12
- package/app-template/src/assets/icons/check.svg +2 -18
- package/app-template/src/assets/icons/chevron-down.svg +2 -7
- package/app-template/src/assets/icons/delete.svg +3 -0
- package/app-template/src/assets/icons/facebook.svg +2 -8
- package/app-template/src/assets/icons/fav-off.svg +5 -0
- package/app-template/src/assets/icons/fav-on.svg +5 -0
- package/app-template/src/assets/icons/filter-and-sort.svg +3 -0
- package/app-template/src/assets/icons/heart.svg +3 -0
- package/app-template/src/assets/icons/instagram.svg +2 -13
- package/app-template/src/assets/icons/materials.svg +3 -0
- package/app-template/src/assets/icons/person.svg +4 -0
- package/app-template/src/assets/icons/pinterest.svg +5 -11
- package/app-template/src/assets/icons/ruler.svg +3 -0
- package/app-template/src/assets/icons/search.svg +8 -11
- package/app-template/src/assets/icons/share.svg +2 -9
- package/app-template/src/assets/icons/snapchat.svg +3 -0
- package/app-template/src/assets/icons/tiktok.svg +3 -0
- package/app-template/src/assets/icons/tumblr.svg +6 -0
- package/app-template/src/assets/icons/twitter.svg +2 -10
- package/app-template/src/assets/icons/vimeo.svg +3 -0
- package/app-template/src/assets/icons/youtube.svg +3 -0
- package/app-template/src/assets/icons/zoom.svg +8 -0
- package/app-template/src/components/accordion.tsx +33 -11
- package/app-template/src/components/action-tooltip.tsx +160 -0
- package/app-template/src/components/currency-select.tsx +149 -4
- package/app-template/src/components/icon.tsx +5 -6
- package/app-template/src/components/index.ts +4 -1
- package/app-template/src/components/language-select.tsx +88 -2
- package/app-template/src/components/pagination.tsx +132 -20
- package/app-template/src/components/quantity-input.tsx +63 -0
- package/app-template/src/components/quantity-selector.tsx +203 -0
- package/app-template/src/components/route-handler.tsx +50 -0
- package/app-template/src/components/select.tsx +89 -69
- package/app-template/src/components/types/index.ts +26 -0
- package/app-template/src/components/widget-content.tsx +323 -0
- package/app-template/src/data/server/theme.ts +70 -0
- package/app-template/src/hooks/use-fav-button.tsx +5 -2
- package/app-template/src/hooks/use-product-cart.ts +11 -8
- package/app-template/src/hooks/use-theme-settings.ts +42 -0
- package/app-template/src/lib/fonts.ts +149 -0
- package/app-template/src/settings.js +2 -2
- package/app-template/src/types/hookform-resolvers-yup.d.ts +28 -0
- package/app-template/src/types/widget.ts +169 -0
- package/app-template/src/utils/formatDate.ts +48 -0
- package/app-template/src/utils/styles.ts +71 -0
- package/app-template/src/views/account/contact-form.tsx +147 -130
- package/app-template/src/views/basket/basket-item.tsx +691 -107
- package/app-template/src/views/basket/basket-summary-context.tsx +560 -0
- package/app-template/src/views/basket/designer-context.tsx +617 -0
- package/app-template/src/views/basket/index.ts +2 -0
- package/app-template/src/views/basket/summary.tsx +496 -75
- package/app-template/src/views/breadcrumb/breadcrumb-client.tsx +190 -0
- package/app-template/src/views/breadcrumb/breadcrumb-registrar.tsx +286 -0
- package/app-template/src/views/breadcrumb/constants.ts +15 -0
- package/app-template/src/views/breadcrumb/index.tsx +127 -0
- package/app-template/src/views/breadcrumb.tsx +13 -38
- package/app-template/src/views/category/category-banner.tsx +4 -23
- package/app-template/src/views/category/category-header.tsx +289 -66
- package/app-template/src/views/category/category-info.tsx +173 -24
- package/app-template/src/views/category/filters/filter-item.tsx +138 -42
- package/app-template/src/views/category/filters/index.tsx +208 -48
- package/app-template/src/views/category/layout.tsx +7 -4
- package/app-template/src/views/category/native-widget-context.tsx +257 -0
- package/app-template/src/views/category/product-list-registrar.tsx +665 -0
- package/app-template/src/views/checkout/auth.tsx +64 -40
- package/app-template/src/views/checkout/checkout-address-registrar.tsx +254 -0
- package/app-template/src/views/checkout/checkout-buttons-registrar.tsx +183 -0
- package/app-template/src/views/checkout/checkout-delivery-method-registrar.tsx +259 -0
- package/app-template/src/views/checkout/checkout-payment-options-registrar.tsx +253 -0
- package/app-template/src/views/checkout/checkout-summary-registrar.tsx +183 -0
- package/app-template/src/views/checkout/constants.ts +5 -0
- package/app-template/src/views/checkout/index.tsx +5 -0
- package/app-template/src/views/checkout/layout/header.tsx +9 -5
- package/app-template/src/views/checkout/steps/payment/index.tsx +5 -2
- package/app-template/src/views/checkout/steps/payment/options/credit-card/index.tsx +72 -1
- package/app-template/src/views/checkout/steps/payment/options/masterpass-rest.tsx +15 -0
- package/app-template/src/views/checkout/steps/payment/options/saved-card.tsx +18 -0
- package/app-template/src/views/checkout/steps/payment/payment-option-buttons.tsx +171 -40
- package/app-template/src/views/checkout/steps/shipping/address-box.tsx +74 -12
- package/app-template/src/views/checkout/steps/shipping/addresses.tsx +128 -45
- package/app-template/src/views/checkout/steps/shipping/shipping-options.tsx +232 -27
- package/app-template/src/views/checkout/summary.tsx +303 -29
- package/app-template/src/views/footer/footer-app-banner-context.tsx +326 -0
- package/app-template/src/views/footer/footer-bottom-context.tsx +215 -0
- package/app-template/src/views/footer/footer-bottom-wrapper.tsx +74 -0
- package/app-template/src/views/footer/footer-layout-constants.ts +35 -0
- package/app-template/src/views/footer/footer-layout-registrar.tsx +342 -0
- package/app-template/src/views/footer/footer-layout-switcher.tsx +110 -0
- package/app-template/src/views/footer/footer-menu-context.tsx +211 -0
- package/app-template/src/views/footer/footer-native-widgets.tsx +60 -0
- package/app-template/src/views/footer/footer-social-context.tsx +254 -0
- package/app-template/src/views/footer/footer-subscription-context.tsx +210 -0
- package/app-template/src/views/footer/footer-utils.ts +43 -0
- package/app-template/src/views/footer/footer-value-props-context.tsx +326 -0
- package/app-template/src/views/footer/logo-settings.ts +183 -0
- package/app-template/src/views/footer/native-widget-config.ts +262 -0
- package/app-template/src/views/footer/subscription-settings.ts +122 -0
- package/app-template/src/views/footer/use-footer-logo.ts +162 -0
- package/app-template/src/views/footer.tsx +415 -13
- package/app-template/src/views/guest-login/index.tsx +62 -58
- package/app-template/src/views/header/action-menu.tsx +277 -45
- package/app-template/src/views/header/band.tsx +6 -21
- package/app-template/src/views/header/designer-context.tsx +261 -0
- package/app-template/src/views/header/header-announcement-registrar.tsx +267 -0
- package/app-template/src/views/header/header-client-wrapper.tsx +496 -0
- package/app-template/src/views/header/header-content.tsx +1026 -0
- package/app-template/src/views/header/header-currency-registrar.tsx +348 -0
- package/app-template/src/views/header/header-icons-context.tsx +262 -0
- package/app-template/src/views/header/header-language-registrar.tsx +348 -0
- package/app-template/src/views/header/header-layout-context.tsx +143 -0
- package/app-template/src/views/header/header-layout-registrar.tsx +658 -0
- package/app-template/src/views/header/header-logo-context.tsx +228 -0
- package/app-template/src/views/header/header-logo.tsx +118 -0
- package/app-template/src/views/header/header-mini-basket-context.tsx +524 -0
- package/app-template/src/views/header/header-search-registrar.tsx +511 -0
- package/app-template/src/views/header/header-text-slider-registrar.tsx +382 -0
- package/app-template/src/views/header/index.tsx +109 -47
- package/app-template/src/views/header/inline-search.tsx +262 -0
- package/app-template/src/views/header/mini-basket.tsx +819 -44
- package/app-template/src/views/header/mobile-hamburger-button.tsx +5 -8
- package/app-template/src/views/header/mobile-menu.tsx +12 -0
- package/app-template/src/views/header/navbar-menu-context.tsx +219 -0
- package/app-template/src/views/header/navbar.tsx +178 -111
- package/app-template/src/views/header/search/index.tsx +71 -32
- package/app-template/src/views/header/search/results.tsx +127 -65
- package/app-template/src/views/header/search/search-input.tsx +61 -0
- package/app-template/src/views/header/server-settings-parser.ts +1105 -0
- package/app-template/src/views/header/use-header-icons.ts +241 -0
- package/app-template/src/views/header/use-header-logo.ts +213 -0
- package/app-template/src/views/header/use-navbar-menu.ts +179 -0
- package/app-template/src/views/login/index.tsx +54 -46
- package/app-template/src/views/product/accordion-section.tsx +61 -0
- package/app-template/src/views/product/accordion-wrapper.tsx +135 -43
- package/app-template/src/views/product/custom-button-group.tsx +69 -0
- package/app-template/src/views/product/favorites-button-section.tsx +69 -0
- package/app-template/src/views/product/find-in-store-section.tsx +60 -0
- package/app-template/src/views/product/index.ts +1 -0
- package/app-template/src/views/product/layout.tsx +6 -5
- package/app-template/src/views/product/misc-buttons.tsx +339 -25
- package/app-template/src/views/product/price-wrapper.tsx +3 -29
- package/app-template/src/views/product/product-actions.tsx +137 -8
- package/app-template/src/views/product/product-info-section.tsx +140 -0
- package/app-template/src/views/product/product-info.tsx +69 -31
- package/app-template/src/views/product/product-share.tsx +13 -8
- package/app-template/src/views/product/product-variants.tsx +2 -2
- package/app-template/src/views/product/quantity-section.tsx +73 -0
- package/app-template/src/views/product/sale-tag.tsx +10 -0
- package/app-template/src/views/product/share-section.tsx +357 -0
- package/app-template/src/views/product/slider.tsx +117 -79
- package/app-template/src/views/product/variant.tsx +69 -41
- package/app-template/src/views/product/variants-section.tsx +126 -0
- package/app-template/src/views/product-detail/constants.ts +272 -0
- package/app-template/src/views/product-detail/index.ts +10 -0
- package/app-template/src/views/product-detail/product-detail-registrar.tsx +616 -0
- package/app-template/src/views/product-item/index.tsx +119 -46
- package/app-template/src/views/register/index.tsx +14 -25
- package/app-template/src/views/share/index.tsx +9 -6
- package/app-template/src/views/widgets/home-hero-slider-content.tsx +41 -39
- package/app-template/src/widgets/flatpages/about-us/index.tsx +78 -0
- package/app-template/src/widgets/flatpages/blog-list/index.tsx +129 -0
- package/app-template/src/widgets/footer-app-banner.tsx +444 -0
- package/app-template/src/widgets/footer-bottom.tsx +127 -0
- package/app-template/src/widgets/footer-menu-compact.tsx +238 -0
- package/app-template/src/widgets/footer-menu-two.tsx +298 -0
- package/app-template/src/widgets/footer-social-client.tsx +251 -0
- package/app-template/src/widgets/footer-social.tsx +47 -16
- package/app-template/src/widgets/footer-subscription/footer-subscription-form.tsx +17 -14
- package/app-template/src/widgets/footer-subscription/index.tsx +183 -17
- package/app-template/src/widgets/footer-value-props.tsx +201 -0
- package/app-template/src/widgets/index.ts +7 -0
- package/app-template/src/widgets/schemas/about-us.json +46 -0
- package/app-template/src/widgets/schemas/blog-list.json +37 -0
- package/app-template/src/widgets/schemas/blog.json +29 -0
- package/app-template/tailwind.config.js +18 -2
- package/package.json +1 -1
|
@@ -9,6 +9,11 @@ import { Select } from './select';
|
|
|
9
9
|
|
|
10
10
|
interface CurrencySelectProps {
|
|
11
11
|
className?: string;
|
|
12
|
+
showIcon?: boolean;
|
|
13
|
+
/** Custom SVG icon content */
|
|
14
|
+
customIcon?: string;
|
|
15
|
+
/** Label format: 'full' (US Dollar), 'symbol' ($), 'code' (USD) */
|
|
16
|
+
labelFormat?: 'full' | 'symbol' | 'code';
|
|
12
17
|
}
|
|
13
18
|
|
|
14
19
|
export const CurrencySelect = (props: CurrencySelectProps) => {
|
|
@@ -17,6 +22,98 @@ export const CurrencySelect = (props: CurrencySelectProps) => {
|
|
|
17
22
|
const { t, currency, setCurrency } = useLocalization();
|
|
18
23
|
const { currencies } = settings.localization;
|
|
19
24
|
|
|
25
|
+
// Currency symbol map for common currencies
|
|
26
|
+
const currencySymbolMap: Record<string, string> = {
|
|
27
|
+
usd: '$',
|
|
28
|
+
eur: '€',
|
|
29
|
+
gbp: '£',
|
|
30
|
+
try: '₺',
|
|
31
|
+
jpy: '¥',
|
|
32
|
+
cny: '¥',
|
|
33
|
+
krw: '₩',
|
|
34
|
+
inr: '₹',
|
|
35
|
+
rub: '₽',
|
|
36
|
+
brl: 'R$',
|
|
37
|
+
aud: 'A$',
|
|
38
|
+
cad: 'C$',
|
|
39
|
+
chf: 'CHF',
|
|
40
|
+
sek: 'kr',
|
|
41
|
+
nok: 'kr',
|
|
42
|
+
dkk: 'kr',
|
|
43
|
+
pln: 'zł',
|
|
44
|
+
mxn: '$',
|
|
45
|
+
sgd: 'S$',
|
|
46
|
+
hkd: 'HK$',
|
|
47
|
+
nzd: 'NZ$',
|
|
48
|
+
zar: 'R',
|
|
49
|
+
aed: 'د.إ',
|
|
50
|
+
sar: '﷼',
|
|
51
|
+
thb: '฿',
|
|
52
|
+
myr: 'RM',
|
|
53
|
+
php: '₱',
|
|
54
|
+
idr: 'Rp',
|
|
55
|
+
vnd: '₫',
|
|
56
|
+
egp: 'E£',
|
|
57
|
+
ngn: '₦',
|
|
58
|
+
pkr: '₨',
|
|
59
|
+
bdt: '৳',
|
|
60
|
+
cop: '$',
|
|
61
|
+
ars: '$',
|
|
62
|
+
clp: '$',
|
|
63
|
+
pen: 'S/',
|
|
64
|
+
ils: '₪',
|
|
65
|
+
kwd: 'د.ك',
|
|
66
|
+
qar: '﷼',
|
|
67
|
+
bhd: '.د.ب',
|
|
68
|
+
omr: '﷼'
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Currency full name map for common currencies
|
|
72
|
+
const currencyNameMap: Record<string, string> = {
|
|
73
|
+
usd: 'US Dollar',
|
|
74
|
+
eur: 'Euro',
|
|
75
|
+
gbp: 'British Pound',
|
|
76
|
+
try: 'Turkish Lira',
|
|
77
|
+
jpy: 'Japanese Yen',
|
|
78
|
+
cny: 'Chinese Yuan',
|
|
79
|
+
krw: 'South Korean Won',
|
|
80
|
+
inr: 'Indian Rupee',
|
|
81
|
+
rub: 'Russian Ruble',
|
|
82
|
+
brl: 'Brazilian Real',
|
|
83
|
+
aud: 'Australian Dollar',
|
|
84
|
+
cad: 'Canadian Dollar',
|
|
85
|
+
chf: 'Swiss Franc',
|
|
86
|
+
sek: 'Swedish Krona',
|
|
87
|
+
nok: 'Norwegian Krone',
|
|
88
|
+
dkk: 'Danish Krone',
|
|
89
|
+
pln: 'Polish Zloty',
|
|
90
|
+
mxn: 'Mexican Peso',
|
|
91
|
+
sgd: 'Singapore Dollar',
|
|
92
|
+
hkd: 'Hong Kong Dollar',
|
|
93
|
+
nzd: 'New Zealand Dollar',
|
|
94
|
+
zar: 'South African Rand',
|
|
95
|
+
aed: 'UAE Dirham',
|
|
96
|
+
sar: 'Saudi Riyal',
|
|
97
|
+
thb: 'Thai Baht',
|
|
98
|
+
myr: 'Malaysian Ringgit',
|
|
99
|
+
php: 'Philippine Peso',
|
|
100
|
+
idr: 'Indonesian Rupiah',
|
|
101
|
+
vnd: 'Vietnamese Dong',
|
|
102
|
+
egp: 'Egyptian Pound',
|
|
103
|
+
ngn: 'Nigerian Naira',
|
|
104
|
+
pkr: 'Pakistani Rupee',
|
|
105
|
+
bdt: 'Bangladeshi Taka',
|
|
106
|
+
cop: 'Colombian Peso',
|
|
107
|
+
ars: 'Argentine Peso',
|
|
108
|
+
clp: 'Chilean Peso',
|
|
109
|
+
pen: 'Peruvian Sol',
|
|
110
|
+
ils: 'Israeli Shekel',
|
|
111
|
+
kwd: 'Kuwaiti Dinar',
|
|
112
|
+
qar: 'Qatari Riyal',
|
|
113
|
+
bhd: 'Bahraini Dinar',
|
|
114
|
+
omr: 'Omani Rial'
|
|
115
|
+
};
|
|
116
|
+
|
|
20
117
|
const handleChange = async (e) => {
|
|
21
118
|
setSelectedCurrency(e.currentTarget.value);
|
|
22
119
|
setIsModalOpen(true);
|
|
@@ -26,16 +123,64 @@ export const CurrencySelect = (props: CurrencySelectProps) => {
|
|
|
26
123
|
setCurrency(selectedCurrency);
|
|
27
124
|
};
|
|
28
125
|
|
|
126
|
+
// Get currency symbol from map or use provided symbol
|
|
127
|
+
const getCurrencySymbol = (curr: { code: string; symbol?: string }) => {
|
|
128
|
+
if (curr.symbol) return curr.symbol;
|
|
129
|
+
return (
|
|
130
|
+
currencySymbolMap[curr.code.toLowerCase()] || curr.code.toUpperCase()
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// Get currency full name from map or use provided label
|
|
135
|
+
const getCurrencyName = (curr: { code: string; label: string }) => {
|
|
136
|
+
const name = currencyNameMap[curr.code.toLowerCase()];
|
|
137
|
+
// If name exists in map, use it. Otherwise check if label looks like a full name (not just code)
|
|
138
|
+
if (name) return name;
|
|
139
|
+
// If label is different from code, assume it's a proper name
|
|
140
|
+
if (curr.label.toLowerCase() !== curr.code.toLowerCase()) return curr.label;
|
|
141
|
+
// Fallback to code uppercase
|
|
142
|
+
return curr.code.toUpperCase();
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// Format label based on labelFormat prop
|
|
146
|
+
const formatLabel = (curr: {
|
|
147
|
+
code: string;
|
|
148
|
+
label: string;
|
|
149
|
+
symbol?: string;
|
|
150
|
+
}) => {
|
|
151
|
+
switch (props.labelFormat) {
|
|
152
|
+
case 'symbol':
|
|
153
|
+
// Return currency symbol ($, €, etc.)
|
|
154
|
+
return getCurrencySymbol(curr);
|
|
155
|
+
case 'code':
|
|
156
|
+
// Return currency code (USD, EUR, etc.)
|
|
157
|
+
return curr.code.toUpperCase();
|
|
158
|
+
case 'full':
|
|
159
|
+
default:
|
|
160
|
+
// Return full label (US Dollar, Euro, etc.)
|
|
161
|
+
return getCurrencyName(curr);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// Check if customIcon has actual SVG content
|
|
166
|
+
const hasValidCustomIcon =
|
|
167
|
+
props.customIcon &&
|
|
168
|
+
typeof props.customIcon === 'string' &&
|
|
169
|
+
props.customIcon.includes('<svg');
|
|
170
|
+
|
|
29
171
|
return (
|
|
30
172
|
<>
|
|
31
173
|
<Select
|
|
32
174
|
onChange={handleChange}
|
|
33
|
-
options={currencies.map((
|
|
34
|
-
value:
|
|
35
|
-
label:
|
|
175
|
+
options={currencies.map((curr) => ({
|
|
176
|
+
value: curr.code,
|
|
177
|
+
label: formatLabel(curr)
|
|
36
178
|
}))}
|
|
37
179
|
value={currency}
|
|
38
|
-
icon=
|
|
180
|
+
icon={
|
|
181
|
+
props.showIcon !== false && !hasValidCustomIcon ? 'money' : undefined
|
|
182
|
+
}
|
|
183
|
+
customIcon={props.showIcon !== false ? props.customIcon : undefined}
|
|
39
184
|
data-testid="currency"
|
|
40
185
|
borderless
|
|
41
186
|
className={props.className}
|
|
@@ -2,17 +2,16 @@ import { IconProps } from '@theme/components/types';
|
|
|
2
2
|
import clsx from 'clsx';
|
|
3
3
|
|
|
4
4
|
export const Icon = (props: IconProps) => {
|
|
5
|
-
const { name, size, className, ...rest } = props;
|
|
5
|
+
const { name, size, className, style, ...rest } = props;
|
|
6
6
|
|
|
7
7
|
return (
|
|
8
8
|
<i
|
|
9
9
|
className={clsx(`flex pz-icon-${name}`, className)}
|
|
10
10
|
{...rest}
|
|
11
|
-
style={
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
11
|
+
style={{
|
|
12
|
+
...style,
|
|
13
|
+
...(size && { fontSize: `${size}px` })
|
|
14
|
+
}}
|
|
16
15
|
/>
|
|
17
16
|
);
|
|
18
17
|
};
|
|
@@ -18,7 +18,8 @@ export * from './select';
|
|
|
18
18
|
export * from './radio';
|
|
19
19
|
export * from './checkbox';
|
|
20
20
|
export * from './file-input';
|
|
21
|
-
|
|
21
|
+
export * from './widget-content';
|
|
22
|
+
export * from './action-tooltip';
|
|
22
23
|
// Loaders
|
|
23
24
|
export * from './loader-spinner';
|
|
24
25
|
export * from './custom-loader';
|
|
@@ -39,3 +40,5 @@ export * from './skeleton-wrapper';
|
|
|
39
40
|
// Head
|
|
40
41
|
export * from './canonical-url';
|
|
41
42
|
export * from './pwa-tags';
|
|
43
|
+
export * from './quantity-input';
|
|
44
|
+
export * from './quantity-selector';
|
|
@@ -1,30 +1,116 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useLocalization } from '@akinon/next/hooks';
|
|
4
|
+
import { useEffect, useRef } from 'react';
|
|
4
5
|
import { Select } from './select';
|
|
5
6
|
|
|
6
7
|
interface LanguageSelectProps {
|
|
7
8
|
className?: string;
|
|
9
|
+
showIcon?: boolean;
|
|
10
|
+
iconClassName?: string;
|
|
11
|
+
/** Custom SVG icon content */
|
|
12
|
+
customIcon?: string;
|
|
13
|
+
/** Label format: 'full' (English), 'short' (EN), 'code' (en) */
|
|
14
|
+
labelFormat?: 'full' | 'short' | 'code';
|
|
8
15
|
}
|
|
9
16
|
|
|
10
17
|
export const LanguageSelect = (props: LanguageSelectProps) => {
|
|
11
18
|
const { locale, locales, setLocale } = useLocalization();
|
|
19
|
+
const isUpdatingFromParent = useRef(false);
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (window.parent !== window && !isUpdatingFromParent.current) {
|
|
23
|
+
window.parent.postMessage(
|
|
24
|
+
{
|
|
25
|
+
type: 'LOCALE_UPDATE',
|
|
26
|
+
data: {
|
|
27
|
+
locale,
|
|
28
|
+
locales: locales.map((lang) => ({
|
|
29
|
+
value: lang.value,
|
|
30
|
+
label: lang.label
|
|
31
|
+
}))
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
'*'
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
}, [locale, locales]);
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const handleMessage = (event: MessageEvent) => {
|
|
41
|
+
if (event.data?.type === 'LOCALE_UPDATE') {
|
|
42
|
+
const { locale: newLocale } = event.data.data;
|
|
43
|
+
|
|
44
|
+
if (newLocale && newLocale !== locale) {
|
|
45
|
+
isUpdatingFromParent.current = true;
|
|
46
|
+
setLocale(newLocale);
|
|
47
|
+
setTimeout(() => {
|
|
48
|
+
isUpdatingFromParent.current = false;
|
|
49
|
+
}, 100);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
window.addEventListener('message', handleMessage);
|
|
55
|
+
return () => window.removeEventListener('message', handleMessage);
|
|
56
|
+
}, [locale, setLocale]);
|
|
12
57
|
|
|
13
58
|
const handleChange = async (e) => {
|
|
14
59
|
const selectedLanguage = e.currentTarget.value;
|
|
15
60
|
|
|
16
61
|
setLocale(selectedLanguage);
|
|
62
|
+
|
|
63
|
+
if (window.parent !== window) {
|
|
64
|
+
window.parent.postMessage(
|
|
65
|
+
{
|
|
66
|
+
type: 'LOCALE_UPDATE',
|
|
67
|
+
data: {
|
|
68
|
+
locale: selectedLanguage,
|
|
69
|
+
locales: locales.map((lang) => ({
|
|
70
|
+
value: lang.value,
|
|
71
|
+
label: lang.label
|
|
72
|
+
}))
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
'*'
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// Format label based on labelFormat prop
|
|
81
|
+
const formatLabel = (lang: { value: string; label: string }) => {
|
|
82
|
+
switch (props.labelFormat) {
|
|
83
|
+
case 'short':
|
|
84
|
+
// Get first 2 characters uppercase (EN, TR, etc.)
|
|
85
|
+
return lang.value.slice(0, 2).toUpperCase();
|
|
86
|
+
case 'code':
|
|
87
|
+
// Return locale code as-is (en, tr, etc.)
|
|
88
|
+
return lang.value;
|
|
89
|
+
case 'full':
|
|
90
|
+
default:
|
|
91
|
+
// Return full label (English, Türkçe, etc.)
|
|
92
|
+
return lang.label;
|
|
93
|
+
}
|
|
17
94
|
};
|
|
18
95
|
|
|
96
|
+
// Check if customIcon has actual SVG content
|
|
97
|
+
const hasValidCustomIcon =
|
|
98
|
+
props.customIcon &&
|
|
99
|
+
typeof props.customIcon === 'string' &&
|
|
100
|
+
props.customIcon.includes('<svg');
|
|
101
|
+
|
|
19
102
|
return (
|
|
20
103
|
<Select
|
|
21
104
|
onChange={handleChange}
|
|
22
105
|
options={locales.map((lang) => ({
|
|
23
106
|
value: lang.value,
|
|
24
|
-
label: lang
|
|
107
|
+
label: formatLabel(lang)
|
|
25
108
|
}))}
|
|
26
109
|
value={locale}
|
|
27
|
-
icon=
|
|
110
|
+
icon={
|
|
111
|
+
props.showIcon !== false && !hasValidCustomIcon ? 'globe' : undefined
|
|
112
|
+
}
|
|
113
|
+
customIcon={props.showIcon !== false ? props.customIcon : undefined}
|
|
28
114
|
data-testid="language"
|
|
29
115
|
borderless
|
|
30
116
|
className={props.className}
|
|
@@ -8,6 +8,14 @@ import { useLocalization } from '@akinon/next/hooks';
|
|
|
8
8
|
import { useRouter } from '@akinon/next/hooks';
|
|
9
9
|
import { useInView } from 'react-intersection-observer';
|
|
10
10
|
|
|
11
|
+
const parseSafeUrl = (url: string) => {
|
|
12
|
+
try {
|
|
13
|
+
return new URL(url, window.location.origin);
|
|
14
|
+
} catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
11
19
|
export const Pagination = (props: PaginationProps) => {
|
|
12
20
|
const { t } = useLocalization();
|
|
13
21
|
const router = useRouter();
|
|
@@ -26,7 +34,8 @@ export const Pagination = (props: PaginationProps) => {
|
|
|
26
34
|
onPageChange,
|
|
27
35
|
direction,
|
|
28
36
|
render,
|
|
29
|
-
isLoading
|
|
37
|
+
isLoading,
|
|
38
|
+
customStyles
|
|
30
39
|
} = props;
|
|
31
40
|
|
|
32
41
|
const pagination = usePagination(total, limit, currentPage, numberOfPages);
|
|
@@ -96,7 +105,11 @@ export const Pagination = (props: PaginationProps) => {
|
|
|
96
105
|
const handleClick = (e: MouseEvent<HTMLAnchorElement>, url: string) => {
|
|
97
106
|
e.preventDefault();
|
|
98
107
|
|
|
99
|
-
const newUrl =
|
|
108
|
+
const newUrl = parseSafeUrl(url);
|
|
109
|
+
if (!newUrl) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
100
113
|
const page = newUrl.searchParams.get('page');
|
|
101
114
|
|
|
102
115
|
if (page === '1') {
|
|
@@ -117,7 +130,21 @@ export const Pagination = (props: PaginationProps) => {
|
|
|
117
130
|
setNextPage(changingPage);
|
|
118
131
|
}
|
|
119
132
|
|
|
120
|
-
onPageChange
|
|
133
|
+
// Navigate to new page using router if onPageChange is not provided
|
|
134
|
+
if (onPageChange) {
|
|
135
|
+
onPageChange(changingPage);
|
|
136
|
+
} else {
|
|
137
|
+
const currentUrl = parseSafeUrl(window.location.href);
|
|
138
|
+
if (!currentUrl) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
currentUrl.searchParams.set('page', String(changingPage));
|
|
143
|
+
if (changingPage === 1) {
|
|
144
|
+
currentUrl.searchParams.delete('page');
|
|
145
|
+
}
|
|
146
|
+
router.push(currentUrl.pathname + currentUrl.search, undefined);
|
|
147
|
+
}
|
|
121
148
|
};
|
|
122
149
|
|
|
123
150
|
useEffect(() => {
|
|
@@ -156,11 +183,77 @@ export const Pagination = (props: PaginationProps) => {
|
|
|
156
183
|
return <>{render(pagination)}</>;
|
|
157
184
|
}
|
|
158
185
|
|
|
186
|
+
// Custom styles for pagination container
|
|
187
|
+
const containerStyles: React.CSSProperties = {
|
|
188
|
+
marginTop: customStyles?.marginTop || '32px',
|
|
189
|
+
marginBottom: customStyles?.marginBottom || '16px',
|
|
190
|
+
gap: customStyles?.pageGap || '8px'
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// Custom styles for page links (button-like)
|
|
194
|
+
const pageStyles: React.CSSProperties = {
|
|
195
|
+
fontSize: customStyles?.pageFontSize || '14px',
|
|
196
|
+
color: customStyles?.pageColor || '#9ca3af',
|
|
197
|
+
backgroundColor: customStyles?.pageBgColor || 'transparent',
|
|
198
|
+
paddingLeft: customStyles?.pagePaddingX || '8px',
|
|
199
|
+
paddingRight: customStyles?.pagePaddingX || '8px',
|
|
200
|
+
paddingTop: customStyles?.pagePaddingY || '4px',
|
|
201
|
+
paddingBottom: customStyles?.pagePaddingY || '4px',
|
|
202
|
+
borderRadius: customStyles?.pageBorderRadius || '0px',
|
|
203
|
+
borderWidth: customStyles?.pageBorderWidth || '0px',
|
|
204
|
+
borderStyle: 'solid',
|
|
205
|
+
borderColor: customStyles?.pageBorderColor || '#e5e7eb',
|
|
206
|
+
display: 'flex',
|
|
207
|
+
alignItems: 'center',
|
|
208
|
+
justifyContent: 'center'
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const activePageStyles: React.CSSProperties = {
|
|
212
|
+
fontSize: customStyles?.pageFontSize || '14px',
|
|
213
|
+
color: customStyles?.pageActiveColor || '#1a1a1a',
|
|
214
|
+
fontWeight: customStyles?.pageActiveFontWeight || '600',
|
|
215
|
+
backgroundColor: customStyles?.pageActiveBgColor || 'transparent',
|
|
216
|
+
paddingLeft: customStyles?.pagePaddingX || '8px',
|
|
217
|
+
paddingRight: customStyles?.pagePaddingX || '8px',
|
|
218
|
+
paddingTop: customStyles?.pagePaddingY || '4px',
|
|
219
|
+
paddingBottom: customStyles?.pagePaddingY || '4px',
|
|
220
|
+
borderRadius: customStyles?.pageBorderRadius || '0px',
|
|
221
|
+
borderWidth: customStyles?.pageBorderWidth || '0px',
|
|
222
|
+
borderStyle: 'solid',
|
|
223
|
+
borderColor: customStyles?.pageActiveBorderColor || '#1a1a1a',
|
|
224
|
+
display: 'flex',
|
|
225
|
+
alignItems: 'center',
|
|
226
|
+
justifyContent: 'center'
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const arrowStyles: React.CSSProperties = {
|
|
230
|
+
color: customStyles?.arrowColor || '#1a1a1a'
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
// Custom styles for more button
|
|
234
|
+
const buttonStyles: React.CSSProperties = {
|
|
235
|
+
backgroundColor: customStyles?.buttonBgColor || '#000000',
|
|
236
|
+
color: customStyles?.buttonTextColor || '#ffffff',
|
|
237
|
+
borderRadius: customStyles?.buttonBorderRadius || '4px',
|
|
238
|
+
paddingLeft: customStyles?.buttonPaddingX || '20px',
|
|
239
|
+
paddingRight: customStyles?.buttonPaddingX || '20px',
|
|
240
|
+
paddingTop: customStyles?.buttonPaddingY || '12px',
|
|
241
|
+
paddingBottom: customStyles?.buttonPaddingY || '12px'
|
|
242
|
+
};
|
|
243
|
+
|
|
159
244
|
return direction === 'prev' && type !== 'list' ? (
|
|
160
245
|
<>
|
|
161
|
-
<div
|
|
246
|
+
<div
|
|
247
|
+
className="flex items-center justify-center"
|
|
248
|
+
style={{
|
|
249
|
+
marginTop: customStyles?.marginTop,
|
|
250
|
+
marginBottom: customStyles?.marginBottom
|
|
251
|
+
}}
|
|
252
|
+
data-section-id="pagination-section"
|
|
253
|
+
>
|
|
162
254
|
<Button
|
|
163
255
|
className={twMerge('px-5', moreButtonClassName)}
|
|
256
|
+
style={buttonStyles}
|
|
164
257
|
onClick={() => handlePageChange()}
|
|
165
258
|
>
|
|
166
259
|
{isLoading ? (
|
|
@@ -174,15 +267,26 @@ export const Pagination = (props: PaginationProps) => {
|
|
|
174
267
|
) : (
|
|
175
268
|
<>
|
|
176
269
|
{type === 'more' && (
|
|
177
|
-
<div
|
|
270
|
+
<div
|
|
271
|
+
className="flex items-center justify-center"
|
|
272
|
+
style={{
|
|
273
|
+
marginTop: customStyles?.marginTop,
|
|
274
|
+
marginBottom: customStyles?.marginBottom
|
|
275
|
+
}}
|
|
276
|
+
data-section-id="pagination-section"
|
|
277
|
+
>
|
|
178
278
|
<Button
|
|
179
279
|
className={twMerge(
|
|
180
|
-
'
|
|
181
|
-
Number(nextPage) === Number(last)
|
|
182
|
-
? 'bg-gray-600 border-gray-600 pointer-events-none'
|
|
183
|
-
: 'bg-black',
|
|
280
|
+
Number(nextPage) === Number(last) ? 'pointer-events-none' : '',
|
|
184
281
|
moreButtonClassName
|
|
185
282
|
)}
|
|
283
|
+
style={{
|
|
284
|
+
...buttonStyles,
|
|
285
|
+
backgroundColor:
|
|
286
|
+
Number(nextPage) === Number(last)
|
|
287
|
+
? '#6b7280'
|
|
288
|
+
: customStyles?.buttonBgColor || '#000000'
|
|
289
|
+
}}
|
|
186
290
|
onClick={() => handlePageChange()}
|
|
187
291
|
disabled={Number(nextPage) === Number(last)}
|
|
188
292
|
>
|
|
@@ -210,9 +314,11 @@ export const Pagination = (props: PaginationProps) => {
|
|
|
210
314
|
{type === 'list' && (
|
|
211
315
|
<ul
|
|
212
316
|
className={twMerge(
|
|
213
|
-
'
|
|
317
|
+
'flex items-center justify-center',
|
|
214
318
|
containerClassName
|
|
215
319
|
)}
|
|
320
|
+
style={containerStyles}
|
|
321
|
+
data-section-id="pagination-section"
|
|
216
322
|
>
|
|
217
323
|
{prev && currentPage !== 1 && (
|
|
218
324
|
<li>
|
|
@@ -220,9 +326,10 @@ export const Pagination = (props: PaginationProps) => {
|
|
|
220
326
|
onClick={(e) => handleClick(e, prev)}
|
|
221
327
|
href={prev}
|
|
222
328
|
className={twMerge(
|
|
223
|
-
'flex cursor-pointer px-2
|
|
329
|
+
'flex cursor-pointer px-2 items-center',
|
|
224
330
|
prevClassName
|
|
225
331
|
)}
|
|
332
|
+
style={arrowStyles}
|
|
226
333
|
>
|
|
227
334
|
<span><</span>
|
|
228
335
|
<span className="ms-4 hidden lg:inline-block">
|
|
@@ -239,20 +346,24 @@ export const Pagination = (props: PaginationProps) => {
|
|
|
239
346
|
onClick={(e) => handleClick(e, item.url)}
|
|
240
347
|
href={item.url}
|
|
241
348
|
className={twMerge(
|
|
242
|
-
clsx(
|
|
243
|
-
'
|
|
244
|
-
|
|
245
|
-
Number(page) === Number(item?.page)
|
|
246
|
-
? 'font-semibold text-black-800'
|
|
247
|
-
: 'text-gray-400'
|
|
248
|
-
),
|
|
349
|
+
clsx('cursor-pointer px-2 items-center', {
|
|
350
|
+
'pointer-events-none': item.url === null
|
|
351
|
+
}),
|
|
249
352
|
pageClassName
|
|
250
353
|
)}
|
|
354
|
+
style={
|
|
355
|
+
Number(page) === Number(item?.page)
|
|
356
|
+
? activePageStyles
|
|
357
|
+
: pageStyles
|
|
358
|
+
}
|
|
251
359
|
>
|
|
252
360
|
{item?.page}
|
|
253
361
|
</Link>
|
|
254
362
|
) : (
|
|
255
|
-
<span
|
|
363
|
+
<span
|
|
364
|
+
className="flex cursor-default items-center justify-center"
|
|
365
|
+
style={pageStyles}
|
|
366
|
+
>
|
|
256
367
|
{item?.page}
|
|
257
368
|
</span>
|
|
258
369
|
)}
|
|
@@ -265,9 +376,10 @@ export const Pagination = (props: PaginationProps) => {
|
|
|
265
376
|
onClick={(e) => handleClick(e, next)}
|
|
266
377
|
href={next}
|
|
267
378
|
className={twMerge(
|
|
268
|
-
'flex cursor-pointer px-2
|
|
379
|
+
'flex cursor-pointer px-2 items-center',
|
|
269
380
|
nextClassName
|
|
270
381
|
)}
|
|
382
|
+
style={arrowStyles}
|
|
271
383
|
>
|
|
272
384
|
<span className="me-4 hidden lg:inline-block">
|
|
273
385
|
{t('category.pagination.next')}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Button, Icon, LoaderSpinner } from '@theme/components';
|
|
2
|
+
|
|
3
|
+
interface QuantityInputProps {
|
|
4
|
+
quantity: number;
|
|
5
|
+
onChange?: (newQuantity: number) => void;
|
|
6
|
+
min?: number;
|
|
7
|
+
max?: number;
|
|
8
|
+
isLoading?: boolean;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const QuantityInput = ({
|
|
14
|
+
quantity,
|
|
15
|
+
onChange,
|
|
16
|
+
min = 1,
|
|
17
|
+
max = 999,
|
|
18
|
+
isLoading = false,
|
|
19
|
+
disabled = false,
|
|
20
|
+
className = ''
|
|
21
|
+
}: QuantityInputProps) => {
|
|
22
|
+
const handleDecrease = () => {
|
|
23
|
+
if (quantity > min && onChange) {
|
|
24
|
+
onChange(quantity - 1);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const handleIncrease = () => {
|
|
29
|
+
if (quantity < max && onChange) {
|
|
30
|
+
onChange(quantity + 1);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div
|
|
36
|
+
className={`w-[138px] h-11 flex items-center justify-between border p-4 ${className}`}
|
|
37
|
+
>
|
|
38
|
+
<Button
|
|
39
|
+
className="h-auto p-0 hover:bg-transparent hover:text-black"
|
|
40
|
+
appearance="ghost"
|
|
41
|
+
onClick={handleDecrease}
|
|
42
|
+
disabled={disabled || isLoading || quantity <= min}
|
|
43
|
+
>
|
|
44
|
+
<Icon name="minus" size={12} />
|
|
45
|
+
</Button>
|
|
46
|
+
<div>
|
|
47
|
+
{isLoading ? (
|
|
48
|
+
<LoaderSpinner className="w-4 h-4" />
|
|
49
|
+
) : (
|
|
50
|
+
<span>{quantity}</span>
|
|
51
|
+
)}
|
|
52
|
+
</div>
|
|
53
|
+
<Button
|
|
54
|
+
className="h-auto p-0 hover:bg-transparent hover:text-black"
|
|
55
|
+
appearance="ghost"
|
|
56
|
+
onClick={handleIncrease}
|
|
57
|
+
disabled={disabled || isLoading || quantity >= max}
|
|
58
|
+
>
|
|
59
|
+
<Icon name="plus" size={12} />
|
|
60
|
+
</Button>
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
};
|