@webbycrown/webbycommerce 1.2.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -3
- package/admin/app.js +3 -0
- package/admin/jsconfig.json +20 -0
- package/admin/src/components/ApiCollectionsContent.jsx +4626 -0
- package/admin/src/components/CompareContent.jsx +300 -0
- package/admin/src/components/ConfigureContent.jsx +407 -0
- package/admin/src/components/Initializer.jsx +64 -0
- package/admin/src/components/LoginRegisterContent.jsx +280 -0
- package/admin/src/components/PluginIcon.jsx +6 -0
- package/admin/src/components/ShippingTypeContent.jsx +230 -0
- package/admin/src/components/SmtpContent.jsx +316 -0
- package/admin/src/components/WishlistContent.jsx +273 -0
- package/admin/src/index.js +81 -0
- package/admin/src/pages/ApiCollections.jsx +169 -0
- package/admin/src/pages/Configure.jsx +55 -0
- package/admin/src/pages/Settings.jsx +93 -0
- package/admin/src/pluginId.js +4 -0
- package/{dist/_chunks/en-CiQ97iC8.js → admin/src/translations/en.json} +712 -574
- package/bin/setup.js +50 -3
- package/package.json +14 -13
- package/server/bootstrap.js +3 -0
- package/server/register.js +3 -0
- package/server/src/bootstrap.js +3826 -0
- package/server/src/components/content-block.json +37 -0
- package/server/src/components/shipping-zone-location.json +27 -0
- package/server/src/config/index.js +7 -0
- package/server/src/content-types/address/index.js +7 -0
- package/server/src/content-types/address/schema.json +74 -0
- package/server/src/content-types/cart/index.js +61 -0
- package/server/src/content-types/cart-item/index.js +79 -0
- package/server/src/content-types/compare.js +73 -0
- package/server/src/content-types/coupon/index.js +7 -0
- package/server/src/content-types/coupon/schema.json +67 -0
- package/server/src/content-types/index.js +42 -0
- package/server/src/content-types/order/index.js +7 -0
- package/server/src/content-types/order/schema.json +121 -0
- package/server/src/content-types/payment-transaction/index.js +7 -0
- package/server/src/content-types/payment-transaction/schema.json +73 -0
- package/server/src/content-types/product/index.js +7 -0
- package/server/src/content-types/product/schema.json +104 -0
- package/server/src/content-types/product-attribute/index.js +7 -0
- package/server/src/content-types/product-attribute/schema.json +80 -0
- package/server/src/content-types/product-attribute-value/index.js +7 -0
- package/server/src/content-types/product-attribute-value/schema.json +52 -0
- package/server/src/content-types/product-category/index.js +7 -0
- package/server/src/content-types/product-category/schema.json +54 -0
- package/server/src/content-types/product-tag/index.js +7 -0
- package/server/src/content-types/product-tag/schema.json +38 -0
- package/server/src/content-types/product-variation/index.js +7 -0
- package/server/src/content-types/product-variation/schema.json +74 -0
- package/server/src/content-types/shipping-method/index.js +7 -0
- package/server/src/content-types/shipping-method/schema.json +91 -0
- package/server/src/content-types/shipping-rate/index.js +7 -0
- package/server/src/content-types/shipping-rate/schema.json +73 -0
- package/server/src/content-types/shipping-rule/index.js +7 -0
- package/server/src/content-types/shipping-rule/schema.json +84 -0
- package/server/src/content-types/shipping-zone/index.js +7 -0
- package/server/src/content-types/shipping-zone/schema.json +57 -0
- package/server/src/content-types/wishlist.js +66 -0
- package/server/src/controllers/address.js +374 -0
- package/server/src/controllers/auth.js +1409 -0
- package/server/src/controllers/cart.js +337 -0
- package/server/src/controllers/category.js +388 -0
- package/server/src/controllers/compare.js +246 -0
- package/server/src/controllers/controller.js +168 -0
- package/server/src/controllers/ecommerce.js +20 -0
- package/server/src/controllers/index.js +34 -0
- package/server/src/controllers/order.js +1100 -0
- package/server/src/controllers/payment.js +243 -0
- package/server/src/controllers/product.js +1006 -0
- package/server/src/controllers/productTag.js +370 -0
- package/server/src/controllers/productVariation.js +181 -0
- package/server/src/controllers/shipping.js +1046 -0
- package/server/src/controllers/wishlist.js +332 -0
- package/server/src/destroy.js +6 -0
- package/server/src/index.js +26 -0
- package/server/src/middlewares/index.js +4 -0
- package/server/src/policies/index.js +4 -0
- package/server/src/register.js +67 -0
- package/server/src/routes/index.js +1130 -0
- package/server/src/services/cart.js +531 -0
- package/server/src/services/compare.js +300 -0
- package/server/src/services/index.js +16 -0
- package/server/src/services/service.js +19 -0
- package/server/src/services/shipping.js +513 -0
- package/server/src/services/wishlist.js +238 -0
- package/server/src/utils/check-ecommerce-permission.js +204 -0
- package/server/src/utils/extend-user-schema.js +161 -0
- package/server/src/utils/seed-data.js +639 -0
- package/server/src/utils/send-email.js +98 -0
- package/strapi-server.js +1 -6
- package/dist/_chunks/Settings-Bg2JyQ4c.js +0 -31518
- package/dist/_chunks/Settings-BonPzbwr.mjs +0 -31499
- package/dist/_chunks/en-DE15m4xZ.mjs +0 -574
- package/dist/_chunks/index-BWVy9o1d.mjs +0 -128
- package/dist/_chunks/index-NRuOdjd7.js +0 -127
- package/dist/admin/index.js +0 -3
- package/dist/admin/index.mjs +0 -4
- package/dist/robots.txt +0 -3
- package/dist/server/index.js +0 -27336
- package/dist/uploads/.gitkeep +0 -0
- package/dist/uploads/accessories_category_2a5631094b.jpeg +0 -0
- package/dist/uploads/beauty_personal_care_category_57f8a8f1e3.jpeg +0 -0
- package/dist/uploads/books_category_a9a253eada.jpeg +0 -0
- package/dist/uploads/classic_cotton_tshirt_1_cd713425f6.png +0 -0
- package/dist/uploads/clothing_category_d5c60ef07b.jpeg +0 -0
- package/dist/uploads/daviddoe_strapi_adbcd41787.jpeg +0 -0
- package/dist/uploads/electronics_category_fc3e5ef571.jpeg +0 -0
- package/dist/uploads/ergonomic_office_chair_1_c751cffb07.png +0 -0
- package/dist/uploads/home_garden_category_4f6eb3f8d6.jpeg +0 -0
- package/dist/uploads/istockphoto_1188462138_612x612_11f295b9c0.jpg +0 -0
- package/dist/uploads/istockphoto_1188462138_612x612_396fb272fd.jpg +0 -0
- package/dist/uploads/large_daviddoe_strapi_adbcd41787.jpeg +0 -0
- package/dist/uploads/leather_travel_backpack_1_238bc1ae4d.png +0 -0
- package/dist/uploads/mechanical_keyboard_pro_1_0cd391a6ac.png +0 -0
- package/dist/uploads/medium_classic_cotton_tshirt_1_cd713425f6.png +0 -0
- package/dist/uploads/medium_daviddoe_strapi_adbcd41787.jpeg +0 -0
- package/dist/uploads/medium_ergonomic_office_chair_1_c751cffb07.png +0 -0
- package/dist/uploads/medium_leather_travel_backpack_1_238bc1ae4d.png +0 -0
- package/dist/uploads/medium_mechanical_keyboard_pro_1_0cd391a6ac.png +0 -0
- package/dist/uploads/medium_smart_watch_series_5_1_cdc2511fb7.png +0 -0
- package/dist/uploads/medium_smartphone_x_pro_1_c3f0cbd080.png +0 -0
- package/dist/uploads/medium_the_great_gatsby_special_1_2e7c76d997.png +0 -0
- package/dist/uploads/medium_wireless_headphones_1_fa75cd50c3.png +0 -0
- package/dist/uploads/medium_yoga_mat_premium_1_01f9a3b5fa.png +0 -0
- package/dist/uploads/predictive_maintenance_icons_industry_automation_600nw_2685943461_e18a8aa3b0.webp +0 -0
- package/dist/uploads/small_classic_cotton_tshirt_1_cd713425f6.png +0 -0
- package/dist/uploads/small_daviddoe_strapi_adbcd41787.jpeg +0 -0
- package/dist/uploads/small_ergonomic_office_chair_1_c751cffb07.png +0 -0
- package/dist/uploads/small_leather_travel_backpack_1_238bc1ae4d.png +0 -0
- package/dist/uploads/small_mechanical_keyboard_pro_1_0cd391a6ac.png +0 -0
- package/dist/uploads/small_smart_watch_series_5_1_cdc2511fb7.png +0 -0
- package/dist/uploads/small_smartphone_x_pro_1_c3f0cbd080.png +0 -0
- package/dist/uploads/small_the_great_gatsby_special_1_2e7c76d997.png +0 -0
- package/dist/uploads/small_wireless_headphones_1_fa75cd50c3.png +0 -0
- package/dist/uploads/small_yoga_mat_premium_1_01f9a3b5fa.png +0 -0
- package/dist/uploads/smart_watch_series_5_1_cdc2511fb7.png +0 -0
- package/dist/uploads/smartphone_x_pro_1_c3f0cbd080.png +0 -0
- package/dist/uploads/the_great_gatsby_special_1_2e7c76d997.png +0 -0
- package/dist/uploads/thumbnail_accessories_category_2a5631094b.jpeg +0 -0
- package/dist/uploads/thumbnail_beauty_personal_care_category_57f8a8f1e3.jpeg +0 -0
- package/dist/uploads/thumbnail_books_category_a9a253eada.jpeg +0 -0
- package/dist/uploads/thumbnail_classic_cotton_tshirt_1_cd713425f6.png +0 -0
- package/dist/uploads/thumbnail_clothing_category_d5c60ef07b.jpeg +0 -0
- package/dist/uploads/thumbnail_daviddoe_strapi_adbcd41787.jpeg +0 -0
- package/dist/uploads/thumbnail_electronics_category_fc3e5ef571.jpeg +0 -0
- package/dist/uploads/thumbnail_ergonomic_office_chair_1_c751cffb07.png +0 -0
- package/dist/uploads/thumbnail_home_garden_category_4f6eb3f8d6.jpeg +0 -0
- package/dist/uploads/thumbnail_istockphoto_1188462138_612x612_11f295b9c0.jpg +0 -0
- package/dist/uploads/thumbnail_istockphoto_1188462138_612x612_396fb272fd.jpg +0 -0
- package/dist/uploads/thumbnail_leather_travel_backpack_1_238bc1ae4d.png +0 -0
- package/dist/uploads/thumbnail_mechanical_keyboard_pro_1_0cd391a6ac.png +0 -0
- package/dist/uploads/thumbnail_predictive_maintenance_icons_industry_automation_600nw_2685943461_e18a8aa3b0.webp +0 -0
- package/dist/uploads/thumbnail_smart_watch_series_5_1_cdc2511fb7.png +0 -0
- package/dist/uploads/thumbnail_smartphone_x_pro_1_c3f0cbd080.png +0 -0
- package/dist/uploads/thumbnail_the_great_gatsby_special_1_2e7c76d997.png +0 -0
- package/dist/uploads/thumbnail_wireless_headphones_1_fa75cd50c3.png +0 -0
- package/dist/uploads/thumbnail_yoga_mat_premium_1_01f9a3b5fa.png +0 -0
- package/dist/uploads/webby-commerce.png +0 -0
- package/dist/uploads/wireless_headphones_1_fa75cd50c3.png +0 -0
- package/dist/uploads/yoga_mat_premium_1_01f9a3b5fa.png +0 -0
- /package/{dist → server/src}/data/demo-data.json +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { PLUGIN_ID } from '../pluginId';
|
|
3
|
+
|
|
4
|
+
// Fix for Strapi 5.x: Provide checkUserHasPermissions in multiple scopes
|
|
5
|
+
// This is a workaround for a known Strapi 5.x RBAC compatibility issue
|
|
6
|
+
const provideCheckUserHasPermissions = () => {
|
|
7
|
+
const defaultImpl = async () => true;
|
|
8
|
+
|
|
9
|
+
// Provide in multiple scopes to ensure it's accessible
|
|
10
|
+
if (typeof window !== 'undefined') {
|
|
11
|
+
if (!window.checkUserHasPermissions) {
|
|
12
|
+
window.checkUserHasPermissions = defaultImpl;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (typeof globalThis !== 'undefined') {
|
|
17
|
+
if (!globalThis.checkUserHasPermissions) {
|
|
18
|
+
globalThis.checkUserHasPermissions = defaultImpl;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (typeof global !== 'undefined') {
|
|
23
|
+
if (!global.checkUserHasPermissions) {
|
|
24
|
+
global.checkUserHasPermissions = defaultImpl;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Provide immediately at module load
|
|
30
|
+
provideCheckUserHasPermissions();
|
|
31
|
+
|
|
32
|
+
const Initializer = () => {
|
|
33
|
+
const hasInitialized = useRef(false);
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (!hasInitialized.current) {
|
|
37
|
+
hasInitialized.current = true;
|
|
38
|
+
|
|
39
|
+
// Ensure the function is available after React hydration
|
|
40
|
+
provideCheckUserHasPermissions();
|
|
41
|
+
|
|
42
|
+
// Also try to patch it into Strapi's app context if available
|
|
43
|
+
try {
|
|
44
|
+
// This will be called when the app context is available
|
|
45
|
+
const checkInterval = setInterval(() => {
|
|
46
|
+
if (window.strapi?.app && typeof window.strapi.app.checkUserHasPermissions === 'undefined') {
|
|
47
|
+
window.strapi.app.checkUserHasPermissions = async () => true;
|
|
48
|
+
clearInterval(checkInterval);
|
|
49
|
+
}
|
|
50
|
+
}, 100);
|
|
51
|
+
|
|
52
|
+
// Clear after 5 seconds to avoid infinite checking
|
|
53
|
+
setTimeout(() => clearInterval(checkInterval), 5000);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
// Silently fail if we can't access Strapi context
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}, []);
|
|
59
|
+
|
|
60
|
+
return null;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export default Initializer;
|
|
64
|
+
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import React, { useEffect, useState } from 'react';
|
|
4
|
+
import { useIntl } from 'react-intl';
|
|
5
|
+
import {
|
|
6
|
+
Box,
|
|
7
|
+
Flex,
|
|
8
|
+
Typography,
|
|
9
|
+
Button,
|
|
10
|
+
} from '@strapi/design-system';
|
|
11
|
+
import { useFetchClient } from '@strapi/admin/strapi-admin';
|
|
12
|
+
import { PLUGIN_ID } from '../pluginId';
|
|
13
|
+
|
|
14
|
+
const LoginRegisterContent = () => {
|
|
15
|
+
const { formatMessage } = useIntl();
|
|
16
|
+
const fetchClient = useFetchClient();
|
|
17
|
+
const [loading, setLoading] = useState(true);
|
|
18
|
+
const [saving, setSaving] = useState(false);
|
|
19
|
+
const [method, setMethod] = useState('default'); // 'default', 'otp', or 'both'
|
|
20
|
+
const [error, setError] = useState(null);
|
|
21
|
+
const [success, setSuccess] = useState(false);
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
loadSettings();
|
|
25
|
+
}, []);
|
|
26
|
+
|
|
27
|
+
const loadSettings = async () => {
|
|
28
|
+
try {
|
|
29
|
+
setLoading(true);
|
|
30
|
+
setError(null);
|
|
31
|
+
const { data } = await fetchClient.get(`/webbycommerce/settings`);
|
|
32
|
+
if (data.loginRegisterMethod) {
|
|
33
|
+
setMethod(data.loginRegisterMethod);
|
|
34
|
+
}
|
|
35
|
+
} catch (err) {
|
|
36
|
+
console.error('Failed to load login/register settings:', err);
|
|
37
|
+
setError(
|
|
38
|
+
formatMessage({
|
|
39
|
+
id: `${PLUGIN_ID}.settings.loginRegister.load.error`,
|
|
40
|
+
defaultMessage: 'Failed to load settings.',
|
|
41
|
+
})
|
|
42
|
+
);
|
|
43
|
+
} finally {
|
|
44
|
+
setLoading(false);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const handleSave = async () => {
|
|
49
|
+
try {
|
|
50
|
+
setSaving(true);
|
|
51
|
+
setError(null);
|
|
52
|
+
setSuccess(false);
|
|
53
|
+
|
|
54
|
+
await fetchClient.put(`/webbycommerce/settings`, {
|
|
55
|
+
loginRegisterMethod: method,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
setSuccess(true);
|
|
59
|
+
setTimeout(() => setSuccess(false), 3000);
|
|
60
|
+
} catch (err) {
|
|
61
|
+
console.error('Failed to save login/register settings:', err);
|
|
62
|
+
setError(
|
|
63
|
+
formatMessage({
|
|
64
|
+
id: `${PLUGIN_ID}.settings.loginRegister.save.error`,
|
|
65
|
+
defaultMessage: 'Failed to save settings.',
|
|
66
|
+
})
|
|
67
|
+
);
|
|
68
|
+
} finally {
|
|
69
|
+
setSaving(false);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
if (loading) {
|
|
74
|
+
return (
|
|
75
|
+
<Box paddingTop={6}>
|
|
76
|
+
<Typography variant="omega" textColor="neutral600">
|
|
77
|
+
{formatMessage({
|
|
78
|
+
id: `${PLUGIN_ID}.settings.loginRegister.loading`,
|
|
79
|
+
defaultMessage: 'Loading settings...',
|
|
80
|
+
})}
|
|
81
|
+
</Typography>
|
|
82
|
+
</Box>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<Box paddingTop={6}>
|
|
88
|
+
<Typography variant="delta" textColor="neutral800" fontWeight="bold" marginBottom={4}>
|
|
89
|
+
{formatMessage({
|
|
90
|
+
id: `${PLUGIN_ID}.settings.loginRegister.title`,
|
|
91
|
+
defaultMessage: 'Login/Register Configuration',
|
|
92
|
+
})}
|
|
93
|
+
</Typography>
|
|
94
|
+
|
|
95
|
+
<Typography variant="omega" textColor="neutral600" marginBottom={6} display="block">
|
|
96
|
+
{formatMessage({
|
|
97
|
+
id: `${PLUGIN_ID}.settings.loginRegister.description`,
|
|
98
|
+
defaultMessage:
|
|
99
|
+
'Choose the authentication method for user login and registration. Default uses Strapi\'s standard email/password authentication. OTP allows users to login or register using email or mobile number with OTP verification.',
|
|
100
|
+
})}
|
|
101
|
+
</Typography>
|
|
102
|
+
|
|
103
|
+
<Box
|
|
104
|
+
background="neutral0"
|
|
105
|
+
hasRadius
|
|
106
|
+
shadow="filterShadow"
|
|
107
|
+
padding={4}
|
|
108
|
+
style={{ maxWidth: '640px' }}
|
|
109
|
+
>
|
|
110
|
+
<Typography variant="delta" textColor="neutral800" fontWeight="semiBold">
|
|
111
|
+
{formatMessage({
|
|
112
|
+
id: `${PLUGIN_ID}.settings.loginRegister.method.label`,
|
|
113
|
+
defaultMessage: 'Authentication Method',
|
|
114
|
+
})}
|
|
115
|
+
</Typography>
|
|
116
|
+
<Box marginTop={1}>
|
|
117
|
+
<Typography variant="pi" textColor="neutral600">
|
|
118
|
+
{formatMessage({
|
|
119
|
+
id: `${PLUGIN_ID}.settings.loginRegister.method.hint`,
|
|
120
|
+
defaultMessage: 'Select the method users will use to login and register.',
|
|
121
|
+
})}
|
|
122
|
+
</Typography>
|
|
123
|
+
</Box>
|
|
124
|
+
<Box marginTop={4}>
|
|
125
|
+
<Flex direction="column" gap={3} alignItems="start">
|
|
126
|
+
<Box
|
|
127
|
+
as="label"
|
|
128
|
+
padding={3}
|
|
129
|
+
background={method === 'default' ? 'primary100' : 'neutral0'}
|
|
130
|
+
hasRadius
|
|
131
|
+
style={{
|
|
132
|
+
cursor: 'pointer',
|
|
133
|
+
border: `1px solid ${method === 'default' ? '#4945ff' : '#dcdce4'}`,
|
|
134
|
+
}}
|
|
135
|
+
>
|
|
136
|
+
<Flex gap={2} alignItems="flex-start">
|
|
137
|
+
<input
|
|
138
|
+
type="radio"
|
|
139
|
+
name="loginMethod"
|
|
140
|
+
value="default"
|
|
141
|
+
checked={method === 'default'}
|
|
142
|
+
onChange={(e) => setMethod(e.target.value)}
|
|
143
|
+
style={{
|
|
144
|
+
marginTop: '4px',
|
|
145
|
+
cursor: 'pointer',
|
|
146
|
+
}}
|
|
147
|
+
/>
|
|
148
|
+
<Box>
|
|
149
|
+
<Typography variant="omega" textColor="neutral800" fontWeight="semiBold">
|
|
150
|
+
{formatMessage({
|
|
151
|
+
id: `${PLUGIN_ID}.settings.loginRegister.method.default`,
|
|
152
|
+
defaultMessage: 'Default (Email/Password)',
|
|
153
|
+
})}
|
|
154
|
+
</Typography>
|
|
155
|
+
<Typography variant="pi" textColor="neutral600" marginTop={1} display="block">
|
|
156
|
+
{formatMessage({
|
|
157
|
+
id: `${PLUGIN_ID}.settings.loginRegister.method.default.description`,
|
|
158
|
+
defaultMessage:
|
|
159
|
+
'Uses Strapi\'s built-in authentication system with email and password.',
|
|
160
|
+
})}
|
|
161
|
+
</Typography>
|
|
162
|
+
</Box>
|
|
163
|
+
</Flex>
|
|
164
|
+
</Box>
|
|
165
|
+
|
|
166
|
+
<Box
|
|
167
|
+
as="label"
|
|
168
|
+
padding={3}
|
|
169
|
+
background={method === 'otp' ? 'primary100' : 'neutral0'}
|
|
170
|
+
hasRadius
|
|
171
|
+
style={{
|
|
172
|
+
cursor: 'pointer',
|
|
173
|
+
border: `1px solid ${method === 'otp' ? '#4945ff' : '#dcdce4'}`,
|
|
174
|
+
}}
|
|
175
|
+
>
|
|
176
|
+
<Flex gap={2} alignItems="flex-start">
|
|
177
|
+
<input
|
|
178
|
+
type="radio"
|
|
179
|
+
name="loginMethod"
|
|
180
|
+
value="otp"
|
|
181
|
+
checked={method === 'otp'}
|
|
182
|
+
onChange={(e) => setMethod(e.target.value)}
|
|
183
|
+
style={{
|
|
184
|
+
marginTop: '4px',
|
|
185
|
+
cursor: 'pointer',
|
|
186
|
+
}}
|
|
187
|
+
/>
|
|
188
|
+
<Box>
|
|
189
|
+
<Typography variant="omega" textColor="neutral800" fontWeight="semiBold">
|
|
190
|
+
{formatMessage({
|
|
191
|
+
id: `${PLUGIN_ID}.settings.loginRegister.method.otp`,
|
|
192
|
+
defaultMessage: 'OTP (Email/Mobile Verification)',
|
|
193
|
+
})}
|
|
194
|
+
</Typography>
|
|
195
|
+
<Typography variant="pi" textColor="neutral600" marginTop={1} display="block">
|
|
196
|
+
{formatMessage({
|
|
197
|
+
id: `${PLUGIN_ID}.settings.loginRegister.method.otp.description`,
|
|
198
|
+
defaultMessage:
|
|
199
|
+
'Users can login or register using email or mobile number. An OTP (One-Time Password) will be sent for verification.',
|
|
200
|
+
})}
|
|
201
|
+
</Typography>
|
|
202
|
+
</Box>
|
|
203
|
+
</Flex>
|
|
204
|
+
</Box>
|
|
205
|
+
|
|
206
|
+
<Box
|
|
207
|
+
as="label"
|
|
208
|
+
padding={3}
|
|
209
|
+
background={method === 'both' ? 'primary100' : 'neutral0'}
|
|
210
|
+
hasRadius
|
|
211
|
+
style={{
|
|
212
|
+
cursor: 'pointer',
|
|
213
|
+
border: `1px solid ${method === 'both' ? '#4945ff' : '#dcdce4'}`,
|
|
214
|
+
}}
|
|
215
|
+
>
|
|
216
|
+
<Flex gap={2} alignItems="flex-start">
|
|
217
|
+
<input
|
|
218
|
+
type="radio"
|
|
219
|
+
name="loginMethod"
|
|
220
|
+
value="both"
|
|
221
|
+
checked={method === 'both'}
|
|
222
|
+
onChange={(e) => setMethod(e.target.value)}
|
|
223
|
+
style={{
|
|
224
|
+
marginTop: '4px',
|
|
225
|
+
cursor: 'pointer',
|
|
226
|
+
}}
|
|
227
|
+
/>
|
|
228
|
+
<Box>
|
|
229
|
+
<Typography variant="omega" textColor="neutral800" fontWeight="semiBold">
|
|
230
|
+
{formatMessage({
|
|
231
|
+
id: `${PLUGIN_ID}.settings.loginRegister.method.both`,
|
|
232
|
+
defaultMessage: 'Both Methods (Unified)',
|
|
233
|
+
})}
|
|
234
|
+
</Typography>
|
|
235
|
+
<Typography variant="pi" textColor="neutral600" marginTop={1} display="block">
|
|
236
|
+
{formatMessage({
|
|
237
|
+
id: `${PLUGIN_ID}.settings.loginRegister.method.both.description`,
|
|
238
|
+
defaultMessage:
|
|
239
|
+
'Users can choose between OTP or email/password authentication. Use the unified /auth/unified endpoint to support both methods simultaneously.',
|
|
240
|
+
})}
|
|
241
|
+
</Typography>
|
|
242
|
+
</Box>
|
|
243
|
+
</Flex>
|
|
244
|
+
</Box>
|
|
245
|
+
</Flex>
|
|
246
|
+
</Box>
|
|
247
|
+
{error && (
|
|
248
|
+
<Box marginTop={4} padding={3} background="danger100" hasRadius>
|
|
249
|
+
<Typography variant="omega" textColor="danger700">
|
|
250
|
+
{error}
|
|
251
|
+
</Typography>
|
|
252
|
+
</Box>
|
|
253
|
+
)}
|
|
254
|
+
|
|
255
|
+
{success && (
|
|
256
|
+
<Box marginTop={4} padding={3} background="success100" hasRadius>
|
|
257
|
+
<Typography variant="omega" textColor="success700">
|
|
258
|
+
{formatMessage({
|
|
259
|
+
id: `${PLUGIN_ID}.settings.loginRegister.save.success`,
|
|
260
|
+
defaultMessage: 'Settings updated successfully.',
|
|
261
|
+
})}
|
|
262
|
+
</Typography>
|
|
263
|
+
</Box>
|
|
264
|
+
)}
|
|
265
|
+
|
|
266
|
+
<Flex marginTop={6} gap={2}>
|
|
267
|
+
<Button onClick={handleSave} loading={saving} disabled={saving}>
|
|
268
|
+
{formatMessage({
|
|
269
|
+
id: `${PLUGIN_ID}.settings.loginRegister.save`,
|
|
270
|
+
defaultMessage: 'Save settings',
|
|
271
|
+
})}
|
|
272
|
+
</Button>
|
|
273
|
+
</Flex>
|
|
274
|
+
</Box>
|
|
275
|
+
</Box>
|
|
276
|
+
);
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
export default LoginRegisterContent;
|
|
280
|
+
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import React, { useEffect, useState } from 'react';
|
|
4
|
+
import { useIntl } from 'react-intl';
|
|
5
|
+
import {
|
|
6
|
+
Box,
|
|
7
|
+
Flex,
|
|
8
|
+
Typography,
|
|
9
|
+
Button,
|
|
10
|
+
} from '@strapi/design-system';
|
|
11
|
+
import { useFetchClient } from '@strapi/admin/strapi-admin';
|
|
12
|
+
import { PLUGIN_ID } from '../pluginId';
|
|
13
|
+
|
|
14
|
+
const ShippingTypeContent = () => {
|
|
15
|
+
const { formatMessage } = useIntl();
|
|
16
|
+
const fetchClient = useFetchClient();
|
|
17
|
+
const [loading, setLoading] = useState(true);
|
|
18
|
+
const [saving, setSaving] = useState(false);
|
|
19
|
+
const [shippingType, setShippingType] = useState('single'); // 'single' or 'multiple'
|
|
20
|
+
const [error, setError] = useState(null);
|
|
21
|
+
const [success, setSuccess] = useState(false);
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
loadSettings();
|
|
25
|
+
}, []);
|
|
26
|
+
|
|
27
|
+
const loadSettings = async () => {
|
|
28
|
+
try {
|
|
29
|
+
setLoading(true);
|
|
30
|
+
setError(null);
|
|
31
|
+
const { data } = await fetchClient.get(`/webbycommerce/settings`);
|
|
32
|
+
if (data.shippingType) {
|
|
33
|
+
setShippingType(data.shippingType);
|
|
34
|
+
}
|
|
35
|
+
} catch (err) {
|
|
36
|
+
console.error('Failed to load shipping type settings:', err);
|
|
37
|
+
setError(
|
|
38
|
+
formatMessage({
|
|
39
|
+
id: `${PLUGIN_ID}.settings.shippingType.load.error`,
|
|
40
|
+
defaultMessage: 'Failed to load settings.',
|
|
41
|
+
})
|
|
42
|
+
);
|
|
43
|
+
} finally {
|
|
44
|
+
setLoading(false);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const handleSave = async () => {
|
|
49
|
+
try {
|
|
50
|
+
setSaving(true);
|
|
51
|
+
setError(null);
|
|
52
|
+
setSuccess(false);
|
|
53
|
+
|
|
54
|
+
const { data } = await fetchClient.put(`/webbycommerce/settings`, {
|
|
55
|
+
shippingType,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
if (data.shippingType) {
|
|
59
|
+
setShippingType(data.shippingType);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
setSuccess(true);
|
|
63
|
+
setTimeout(() => setSuccess(false), 3000);
|
|
64
|
+
} catch (err) {
|
|
65
|
+
console.error('Failed to save shipping type settings:', err);
|
|
66
|
+
setError(
|
|
67
|
+
formatMessage({
|
|
68
|
+
id: `${PLUGIN_ID}.settings.shippingType.save.error`,
|
|
69
|
+
defaultMessage: 'Failed to save settings. Please try again.',
|
|
70
|
+
})
|
|
71
|
+
);
|
|
72
|
+
} finally {
|
|
73
|
+
setSaving(false);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
if (loading) {
|
|
78
|
+
return (
|
|
79
|
+
<Box padding={4}>
|
|
80
|
+
<Typography>
|
|
81
|
+
{formatMessage({
|
|
82
|
+
id: `${PLUGIN_ID}.settings.shippingType.loading`,
|
|
83
|
+
defaultMessage: 'Loading settings...',
|
|
84
|
+
})}
|
|
85
|
+
</Typography>
|
|
86
|
+
</Box>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<Box>
|
|
92
|
+
<Box paddingBottom={4}>
|
|
93
|
+
<Typography variant="beta" as="h2">
|
|
94
|
+
{formatMessage({
|
|
95
|
+
id: `${PLUGIN_ID}.settings.shippingType.title`,
|
|
96
|
+
defaultMessage: 'Shipping Type Settings',
|
|
97
|
+
})}
|
|
98
|
+
</Typography>
|
|
99
|
+
<Typography variant="omega" textColor="neutral600" as="p" style={{ marginTop: '8px' }}>
|
|
100
|
+
{formatMessage({
|
|
101
|
+
id: `${PLUGIN_ID}.settings.shippingType.description`,
|
|
102
|
+
defaultMessage: 'Configure how users can manage their billing and shipping addresses.',
|
|
103
|
+
})}
|
|
104
|
+
</Typography>
|
|
105
|
+
</Box>
|
|
106
|
+
|
|
107
|
+
<Box paddingBottom={6}>
|
|
108
|
+
<Box paddingBottom={3}>
|
|
109
|
+
<Typography variant="omega" fontWeight="semiBold" as="label" style={{ display: 'block', marginBottom: '8px' }}>
|
|
110
|
+
{formatMessage({
|
|
111
|
+
id: `${PLUGIN_ID}.settings.shippingType.method.label`,
|
|
112
|
+
defaultMessage: 'Address Management Type',
|
|
113
|
+
})}
|
|
114
|
+
</Typography>
|
|
115
|
+
</Box>
|
|
116
|
+
|
|
117
|
+
<Flex direction="column" gap={3} alignItems="start">
|
|
118
|
+
<Box
|
|
119
|
+
as="label"
|
|
120
|
+
padding={4}
|
|
121
|
+
borderColor={shippingType === 'single' ? 'primary600' : 'neutral200'}
|
|
122
|
+
borderStyle="solid"
|
|
123
|
+
borderWidth="1px"
|
|
124
|
+
hasRadius
|
|
125
|
+
style={{
|
|
126
|
+
cursor: 'pointer',
|
|
127
|
+
backgroundColor: shippingType === 'single' ? 'rgba(0, 122, 255, 0.05)' : 'transparent',
|
|
128
|
+
}}
|
|
129
|
+
onClick={() => setShippingType('single')}
|
|
130
|
+
>
|
|
131
|
+
<Flex gap={2} alignItems="center">
|
|
132
|
+
<input
|
|
133
|
+
type="radio"
|
|
134
|
+
name="shippingType"
|
|
135
|
+
value="single"
|
|
136
|
+
checked={shippingType === 'single'}
|
|
137
|
+
onChange={() => setShippingType('single')}
|
|
138
|
+
style={{ margin: 0 }}
|
|
139
|
+
/>
|
|
140
|
+
<Box>
|
|
141
|
+
<Typography variant="omega" fontWeight="semiBold">
|
|
142
|
+
{formatMessage({
|
|
143
|
+
id: `${PLUGIN_ID}.settings.shippingType.single.label`,
|
|
144
|
+
defaultMessage: 'Single Address Mode',
|
|
145
|
+
})}
|
|
146
|
+
</Typography>
|
|
147
|
+
<Typography variant="omega" textColor="neutral600" style={{ marginTop: '4px' }} display="block">
|
|
148
|
+
{formatMessage({
|
|
149
|
+
id: `${PLUGIN_ID}.settings.shippingType.single.description`,
|
|
150
|
+
defaultMessage: 'Users can have one billing address and one shipping address. Suitable for simple e-commerce sites.',
|
|
151
|
+
})}
|
|
152
|
+
</Typography>
|
|
153
|
+
</Box>
|
|
154
|
+
</Flex>
|
|
155
|
+
</Box>
|
|
156
|
+
|
|
157
|
+
<Box
|
|
158
|
+
as="label"
|
|
159
|
+
padding={4}
|
|
160
|
+
borderColor={shippingType === 'multiple' ? 'primary600' : 'neutral200'}
|
|
161
|
+
borderStyle="solid"
|
|
162
|
+
borderWidth="1px"
|
|
163
|
+
hasRadius
|
|
164
|
+
style={{
|
|
165
|
+
cursor: 'pointer',
|
|
166
|
+
backgroundColor: shippingType === 'multiple' ? 'rgba(0, 122, 255, 0.05)' : 'transparent',
|
|
167
|
+
}}
|
|
168
|
+
onClick={() => setShippingType('multiple')}
|
|
169
|
+
>
|
|
170
|
+
<Flex gap={2} alignItems="center">
|
|
171
|
+
<input
|
|
172
|
+
type="radio"
|
|
173
|
+
name="shippingType"
|
|
174
|
+
value="multiple"
|
|
175
|
+
checked={shippingType === 'multiple'}
|
|
176
|
+
onChange={() => setShippingType('multiple')}
|
|
177
|
+
style={{ margin: 0 }}
|
|
178
|
+
/>
|
|
179
|
+
<Box>
|
|
180
|
+
<Typography variant="omega" fontWeight="semiBold">
|
|
181
|
+
{formatMessage({
|
|
182
|
+
id: `${PLUGIN_ID}.settings.shippingType.multiple.label`,
|
|
183
|
+
defaultMessage: 'Multiple Address Mode',
|
|
184
|
+
})}
|
|
185
|
+
</Typography>
|
|
186
|
+
<Typography variant="omega" textColor="neutral600" style={{ marginTop: '4px' }} display="block">
|
|
187
|
+
{formatMessage({
|
|
188
|
+
id: `${PLUGIN_ID}.settings.shippingType.multiple.description`,
|
|
189
|
+
defaultMessage: 'Users can have multiple billing and shipping addresses. They can select any address during checkout. Similar to Amazon/Flipkart.',
|
|
190
|
+
})}
|
|
191
|
+
</Typography>
|
|
192
|
+
</Box>
|
|
193
|
+
</Flex>
|
|
194
|
+
</Box>
|
|
195
|
+
</Flex>
|
|
196
|
+
</Box>
|
|
197
|
+
|
|
198
|
+
{error && (
|
|
199
|
+
<Box paddingBottom={4}>
|
|
200
|
+
<Typography textColor="danger600" variant="omega">
|
|
201
|
+
{error}
|
|
202
|
+
</Typography>
|
|
203
|
+
</Box>
|
|
204
|
+
)}
|
|
205
|
+
|
|
206
|
+
{success && (
|
|
207
|
+
<Box paddingBottom={4}>
|
|
208
|
+
<Typography textColor="success600" variant="omega">
|
|
209
|
+
{formatMessage({
|
|
210
|
+
id: `${PLUGIN_ID}.settings.shippingType.save.success`,
|
|
211
|
+
defaultMessage: 'Settings saved successfully!',
|
|
212
|
+
})}
|
|
213
|
+
</Typography>
|
|
214
|
+
</Box>
|
|
215
|
+
)}
|
|
216
|
+
|
|
217
|
+
<Flex justifyContent="flex-start">
|
|
218
|
+
<Button onClick={handleSave} loading={saving} disabled={saving}>
|
|
219
|
+
{formatMessage({
|
|
220
|
+
id: `${PLUGIN_ID}.settings.shippingType.save.button`,
|
|
221
|
+
defaultMessage: 'Save Settings',
|
|
222
|
+
})}
|
|
223
|
+
</Button>
|
|
224
|
+
</Flex>
|
|
225
|
+
</Box>
|
|
226
|
+
);
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
export default ShippingTypeContent;
|
|
230
|
+
|