afront 1.0.24 → 1.0.25
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/.babelrc +13 -13
- package/.env +1 -1
- package/LICENSE +21 -21
- package/README.md +94 -94
- package/build-prod/index.html +1 -1
- package/build-prod/manifest.json +25 -25
- package/build-prod/offline.html +1023 -1023
- package/build-prod/robots.txt +3 -3
- package/build-prod-static/index.html +1 -1
- package/build-prod-static/manifest.json +25 -25
- package/build-prod-static/offline.html +1023 -1023
- package/build-prod-static/robots.txt +3 -3
- package/install.js +415 -415
- package/package.json +102 -96
- package/server.js +40 -40
- package/src/ARoutes/AFRoutes.js +28 -28
- package/src/Api/api.config.js +266 -266
- package/src/Api/login.service.js +44 -44
- package/src/App.js +28 -28
- package/src/Components/Background/MeshGradient.js +18 -18
- package/src/Components/Footer/Footer.js +108 -108
- package/src/Components/Header/Header.js +149 -149
- package/src/Components/Loading/LoadingIndicator.js +12 -12
- package/src/Components/Loading/LoadingIndicator.module.css +34 -34
- package/src/Components/Loading/LoadingSpinner.js +27 -27
- package/src/Components/Loading/LoadingSpinner.module.css +100 -100
- package/src/Components/RequireAuth.js +29 -29
- package/src/LoadingFallback.js +13 -13
- package/src/PageNotFound.js +19 -19
- package/src/Pages/Home.js +50 -50
- package/src/Pages/Signup.js +230 -230
- package/src/Pages/Support.js +68 -68
- package/src/Routes/ARoutes.js +66 -66
- package/src/Routes/ARoutesStatic.js +83 -83
- package/src/Static/appStatic.js +16 -16
- package/src/Static/indexStatic.js +13 -13
- package/src/Style/App.module.css +11 -11
- package/src/Style/MeshGradient.module.css +130 -130
- package/src/Style/PageNotFound.module.css +37 -37
- package/src/Style/Style.module.css +686 -686
- package/src/Style/Support.module.css +185 -185
- package/src/Utils/LoadingContext.js +5 -5
- package/src/index.js +25 -25
- package/webpack.build-prod.js +141 -140
- package/webpack.dev.js +127 -127
- package/webpack.prod.js +148 -147
- package/webpack.ssr.prod.js +97 -97
- package/npm-shrinkwrap.json +0 -9641
package/src/Pages/Signup.js
CHANGED
|
@@ -1,230 +1,230 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
2
|
-
import { useNavigate } from "react-router";
|
|
3
|
-
import auth from "../Api/login.service";
|
|
4
|
-
|
|
5
|
-
function Signup() {
|
|
6
|
-
const navigate = useNavigate();
|
|
7
|
-
const [step, setStep] = useState(1);
|
|
8
|
-
const [email, setEmail] = useState("");
|
|
9
|
-
const [password, setPassword] = useState("");
|
|
10
|
-
const [name, setName] = useState("");
|
|
11
|
-
const [accountType, setAccountType] = useState("personal"); // personal/creator or business
|
|
12
|
-
const [companyName, setCompanyName] = useState("");
|
|
13
|
-
const [loading, setLoading] = useState(false);
|
|
14
|
-
const [error, setError] = useState(null);
|
|
15
|
-
|
|
16
|
-
const validateStep = () => {
|
|
17
|
-
setError(null);
|
|
18
|
-
if (step === 1) {
|
|
19
|
-
if (!email) return "Email is required";
|
|
20
|
-
// basic email regex
|
|
21
|
-
const emailRegex = /^[^@\s]+@[^@\s]+\.[^@\s]+$/;
|
|
22
|
-
if (!emailRegex.test(email)) return "Enter a valid email address";
|
|
23
|
-
if (!password) return "Password is required";
|
|
24
|
-
if (password.length < 8) return "Password must be at least 8 characters";
|
|
25
|
-
}
|
|
26
|
-
if (step === 2) {
|
|
27
|
-
if (!name || name.trim().length === 0) return "Full name is required";
|
|
28
|
-
}
|
|
29
|
-
if (step === 3) {
|
|
30
|
-
if (!accountType) return "Select account type";
|
|
31
|
-
if (
|
|
32
|
-
accountType === "business" &&
|
|
33
|
-
(!companyName || companyName.trim().length === 0)
|
|
34
|
-
)
|
|
35
|
-
return "Brand / Company Name is required for business accounts";
|
|
36
|
-
}
|
|
37
|
-
return null;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const handleNext = (e) => {
|
|
41
|
-
(async () => {
|
|
42
|
-
if (e) e.preventDefault();
|
|
43
|
-
const err = validateStep();
|
|
44
|
-
if (err) return setError(err);
|
|
45
|
-
setError(null);
|
|
46
|
-
// On step 1, call backend to check email (exists/disposable)
|
|
47
|
-
if (step === 1) {
|
|
48
|
-
try {
|
|
49
|
-
const res = await auth.checkSignup({ email });
|
|
50
|
-
if (!res || !res.ok) {
|
|
51
|
-
setError(
|
|
52
|
-
(res && res.data && (res.data.error || res.data.message)) ||
|
|
53
|
-
"Check failed"
|
|
54
|
-
);
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
if (res.data.disposable) {
|
|
58
|
-
setError("Disposable email addresses are not allowed");
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
if (res.data.exists) {
|
|
62
|
-
setError("An account already exists with this email");
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
} catch (err) {
|
|
66
|
-
setError("Email check failed");
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
setStep((s) => Math.min(3, s + 1));
|
|
71
|
-
})();
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
const handleBack = (e) => {
|
|
75
|
-
if (e) e.preventDefault();
|
|
76
|
-
setError(null);
|
|
77
|
-
setStep((s) => Math.max(1, s - 1));
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const handleSubmit = async (e) => {
|
|
81
|
-
if (e) e.preventDefault();
|
|
82
|
-
const err = validateStep();
|
|
83
|
-
if (err) return setError(err);
|
|
84
|
-
setLoading(true);
|
|
85
|
-
setError(null);
|
|
86
|
-
try {
|
|
87
|
-
const payload = {
|
|
88
|
-
email,
|
|
89
|
-
password,
|
|
90
|
-
name,
|
|
91
|
-
accountType,
|
|
92
|
-
companyName: accountType === "business" ? companyName : undefined,
|
|
93
|
-
};
|
|
94
|
-
const res = await auth.signup(payload);
|
|
95
|
-
if (!res || !res.ok) {
|
|
96
|
-
setError(
|
|
97
|
-
(res && res.data && (res.data.error || res.data.message)) ||
|
|
98
|
-
"Registration failed"
|
|
99
|
-
);
|
|
100
|
-
setLoading(false);
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
try {
|
|
105
|
-
localStorage.setItem("auth-event", String(Date.now()));
|
|
106
|
-
} catch (e) {}
|
|
107
|
-
window.dispatchEvent(new Event("auth-changed"));
|
|
108
|
-
navigate("/");
|
|
109
|
-
} catch (err) {
|
|
110
|
-
setError("Registration failed");
|
|
111
|
-
} finally {
|
|
112
|
-
setLoading(false);
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
return (
|
|
117
|
-
<div className="page auth-page signup-page">
|
|
118
|
-
<h2>Sign up</h2>
|
|
119
|
-
{error && <div className="auth-error">{error}</div>}
|
|
120
|
-
<form
|
|
121
|
-
className="auth-form"
|
|
122
|
-
onSubmit={step === 3 ? handleSubmit : handleNext}>
|
|
123
|
-
{step === 1 && (
|
|
124
|
-
<>
|
|
125
|
-
<label>
|
|
126
|
-
Email Address (required)
|
|
127
|
-
<input
|
|
128
|
-
type="email"
|
|
129
|
-
value={email}
|
|
130
|
-
onChange={(e) => setEmail(e.target.value)}
|
|
131
|
-
disabled={loading}
|
|
132
|
-
/>
|
|
133
|
-
</label>
|
|
134
|
-
{/* Work/personal choice removed — backend tracks only personal emails */}
|
|
135
|
-
<label>
|
|
136
|
-
Password (required, min 8 characters)
|
|
137
|
-
<input
|
|
138
|
-
type="password"
|
|
139
|
-
value={password}
|
|
140
|
-
onChange={(e) => setPassword(e.target.value)}
|
|
141
|
-
disabled={loading}
|
|
142
|
-
/>
|
|
143
|
-
</label>
|
|
144
|
-
<div className="form-actions">
|
|
145
|
-
<button type="button" onClick={handleNext} disabled={loading}>
|
|
146
|
-
Next
|
|
147
|
-
</button>
|
|
148
|
-
</div>
|
|
149
|
-
</>
|
|
150
|
-
)}
|
|
151
|
-
|
|
152
|
-
{step === 2 && (
|
|
153
|
-
<>
|
|
154
|
-
<label>
|
|
155
|
-
Full Name (required)
|
|
156
|
-
<input
|
|
157
|
-
value={name}
|
|
158
|
-
onChange={(e) => setName(e.target.value)}
|
|
159
|
-
disabled={loading}
|
|
160
|
-
/>
|
|
161
|
-
</label>
|
|
162
|
-
<div className="form-actions">
|
|
163
|
-
<button type="button" onClick={handleBack} disabled={loading}>
|
|
164
|
-
Back
|
|
165
|
-
</button>
|
|
166
|
-
<button type="button" onClick={handleNext} disabled={loading}>
|
|
167
|
-
Next
|
|
168
|
-
</button>
|
|
169
|
-
</div>
|
|
170
|
-
</>
|
|
171
|
-
)}
|
|
172
|
-
|
|
173
|
-
{step === 3 && (
|
|
174
|
-
<>
|
|
175
|
-
<label>
|
|
176
|
-
Account Type (required)
|
|
177
|
-
<div>
|
|
178
|
-
<label>
|
|
179
|
-
<input
|
|
180
|
-
type="radio"
|
|
181
|
-
name="accountType"
|
|
182
|
-
value="personal"
|
|
183
|
-
checked={accountType === "personal"}
|
|
184
|
-
onChange={() => setAccountType("personal")}
|
|
185
|
-
disabled={loading}
|
|
186
|
-
/>
|
|
187
|
-
Personal / Creator
|
|
188
|
-
</label>
|
|
189
|
-
<label>
|
|
190
|
-
<input
|
|
191
|
-
type="radio"
|
|
192
|
-
name="accountType"
|
|
193
|
-
value="business"
|
|
194
|
-
checked={accountType === "business"}
|
|
195
|
-
onChange={() => setAccountType("business")}
|
|
196
|
-
disabled={loading}
|
|
197
|
-
/>
|
|
198
|
-
Business / Brand / Company
|
|
199
|
-
</label>
|
|
200
|
-
</div>
|
|
201
|
-
</label>
|
|
202
|
-
{accountType === "business" && (
|
|
203
|
-
<label>
|
|
204
|
-
Brand / Company Name (required for business)
|
|
205
|
-
<input
|
|
206
|
-
value={companyName}
|
|
207
|
-
onChange={(e) => setCompanyName(e.target.value)}
|
|
208
|
-
disabled={loading}
|
|
209
|
-
/>
|
|
210
|
-
</label>
|
|
211
|
-
)}
|
|
212
|
-
|
|
213
|
-
{error && <div className="auth-error">{error}</div>}
|
|
214
|
-
|
|
215
|
-
<div className="form-actions">
|
|
216
|
-
<button type="button" onClick={handleBack} disabled={loading}>
|
|
217
|
-
Back
|
|
218
|
-
</button>
|
|
219
|
-
<button type="submit" disabled={loading}>
|
|
220
|
-
{loading ? "Signing up..." : "Sign up"}
|
|
221
|
-
</button>
|
|
222
|
-
</div>
|
|
223
|
-
</>
|
|
224
|
-
)}
|
|
225
|
-
</form>
|
|
226
|
-
</div>
|
|
227
|
-
);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
export default Signup;
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { useNavigate } from "react-router";
|
|
3
|
+
import auth from "../Api/login.service";
|
|
4
|
+
|
|
5
|
+
function Signup() {
|
|
6
|
+
const navigate = useNavigate();
|
|
7
|
+
const [step, setStep] = useState(1);
|
|
8
|
+
const [email, setEmail] = useState("");
|
|
9
|
+
const [password, setPassword] = useState("");
|
|
10
|
+
const [name, setName] = useState("");
|
|
11
|
+
const [accountType, setAccountType] = useState("personal"); // personal/creator or business
|
|
12
|
+
const [companyName, setCompanyName] = useState("");
|
|
13
|
+
const [loading, setLoading] = useState(false);
|
|
14
|
+
const [error, setError] = useState(null);
|
|
15
|
+
|
|
16
|
+
const validateStep = () => {
|
|
17
|
+
setError(null);
|
|
18
|
+
if (step === 1) {
|
|
19
|
+
if (!email) return "Email is required";
|
|
20
|
+
// basic email regex
|
|
21
|
+
const emailRegex = /^[^@\s]+@[^@\s]+\.[^@\s]+$/;
|
|
22
|
+
if (!emailRegex.test(email)) return "Enter a valid email address";
|
|
23
|
+
if (!password) return "Password is required";
|
|
24
|
+
if (password.length < 8) return "Password must be at least 8 characters";
|
|
25
|
+
}
|
|
26
|
+
if (step === 2) {
|
|
27
|
+
if (!name || name.trim().length === 0) return "Full name is required";
|
|
28
|
+
}
|
|
29
|
+
if (step === 3) {
|
|
30
|
+
if (!accountType) return "Select account type";
|
|
31
|
+
if (
|
|
32
|
+
accountType === "business" &&
|
|
33
|
+
(!companyName || companyName.trim().length === 0)
|
|
34
|
+
)
|
|
35
|
+
return "Brand / Company Name is required for business accounts";
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const handleNext = (e) => {
|
|
41
|
+
(async () => {
|
|
42
|
+
if (e) e.preventDefault();
|
|
43
|
+
const err = validateStep();
|
|
44
|
+
if (err) return setError(err);
|
|
45
|
+
setError(null);
|
|
46
|
+
// On step 1, call backend to check email (exists/disposable)
|
|
47
|
+
if (step === 1) {
|
|
48
|
+
try {
|
|
49
|
+
const res = await auth.checkSignup({ email });
|
|
50
|
+
if (!res || !res.ok) {
|
|
51
|
+
setError(
|
|
52
|
+
(res && res.data && (res.data.error || res.data.message)) ||
|
|
53
|
+
"Check failed"
|
|
54
|
+
);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (res.data.disposable) {
|
|
58
|
+
setError("Disposable email addresses are not allowed");
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (res.data.exists) {
|
|
62
|
+
setError("An account already exists with this email");
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
} catch (err) {
|
|
66
|
+
setError("Email check failed");
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
setStep((s) => Math.min(3, s + 1));
|
|
71
|
+
})();
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const handleBack = (e) => {
|
|
75
|
+
if (e) e.preventDefault();
|
|
76
|
+
setError(null);
|
|
77
|
+
setStep((s) => Math.max(1, s - 1));
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const handleSubmit = async (e) => {
|
|
81
|
+
if (e) e.preventDefault();
|
|
82
|
+
const err = validateStep();
|
|
83
|
+
if (err) return setError(err);
|
|
84
|
+
setLoading(true);
|
|
85
|
+
setError(null);
|
|
86
|
+
try {
|
|
87
|
+
const payload = {
|
|
88
|
+
email,
|
|
89
|
+
password,
|
|
90
|
+
name,
|
|
91
|
+
accountType,
|
|
92
|
+
companyName: accountType === "business" ? companyName : undefined,
|
|
93
|
+
};
|
|
94
|
+
const res = await auth.signup(payload);
|
|
95
|
+
if (!res || !res.ok) {
|
|
96
|
+
setError(
|
|
97
|
+
(res && res.data && (res.data.error || res.data.message)) ||
|
|
98
|
+
"Registration failed"
|
|
99
|
+
);
|
|
100
|
+
setLoading(false);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
localStorage.setItem("auth-event", String(Date.now()));
|
|
106
|
+
} catch (e) {}
|
|
107
|
+
window.dispatchEvent(new Event("auth-changed"));
|
|
108
|
+
navigate("/");
|
|
109
|
+
} catch (err) {
|
|
110
|
+
setError("Registration failed");
|
|
111
|
+
} finally {
|
|
112
|
+
setLoading(false);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
<div className="page auth-page signup-page">
|
|
118
|
+
<h2>Sign up</h2>
|
|
119
|
+
{error && <div className="auth-error">{error}</div>}
|
|
120
|
+
<form
|
|
121
|
+
className="auth-form"
|
|
122
|
+
onSubmit={step === 3 ? handleSubmit : handleNext}>
|
|
123
|
+
{step === 1 && (
|
|
124
|
+
<>
|
|
125
|
+
<label>
|
|
126
|
+
Email Address (required)
|
|
127
|
+
<input
|
|
128
|
+
type="email"
|
|
129
|
+
value={email}
|
|
130
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
131
|
+
disabled={loading}
|
|
132
|
+
/>
|
|
133
|
+
</label>
|
|
134
|
+
{/* Work/personal choice removed — backend tracks only personal emails */}
|
|
135
|
+
<label>
|
|
136
|
+
Password (required, min 8 characters)
|
|
137
|
+
<input
|
|
138
|
+
type="password"
|
|
139
|
+
value={password}
|
|
140
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
141
|
+
disabled={loading}
|
|
142
|
+
/>
|
|
143
|
+
</label>
|
|
144
|
+
<div className="form-actions">
|
|
145
|
+
<button type="button" onClick={handleNext} disabled={loading}>
|
|
146
|
+
Next
|
|
147
|
+
</button>
|
|
148
|
+
</div>
|
|
149
|
+
</>
|
|
150
|
+
)}
|
|
151
|
+
|
|
152
|
+
{step === 2 && (
|
|
153
|
+
<>
|
|
154
|
+
<label>
|
|
155
|
+
Full Name (required)
|
|
156
|
+
<input
|
|
157
|
+
value={name}
|
|
158
|
+
onChange={(e) => setName(e.target.value)}
|
|
159
|
+
disabled={loading}
|
|
160
|
+
/>
|
|
161
|
+
</label>
|
|
162
|
+
<div className="form-actions">
|
|
163
|
+
<button type="button" onClick={handleBack} disabled={loading}>
|
|
164
|
+
Back
|
|
165
|
+
</button>
|
|
166
|
+
<button type="button" onClick={handleNext} disabled={loading}>
|
|
167
|
+
Next
|
|
168
|
+
</button>
|
|
169
|
+
</div>
|
|
170
|
+
</>
|
|
171
|
+
)}
|
|
172
|
+
|
|
173
|
+
{step === 3 && (
|
|
174
|
+
<>
|
|
175
|
+
<label>
|
|
176
|
+
Account Type (required)
|
|
177
|
+
<div>
|
|
178
|
+
<label>
|
|
179
|
+
<input
|
|
180
|
+
type="radio"
|
|
181
|
+
name="accountType"
|
|
182
|
+
value="personal"
|
|
183
|
+
checked={accountType === "personal"}
|
|
184
|
+
onChange={() => setAccountType("personal")}
|
|
185
|
+
disabled={loading}
|
|
186
|
+
/>
|
|
187
|
+
Personal / Creator
|
|
188
|
+
</label>
|
|
189
|
+
<label>
|
|
190
|
+
<input
|
|
191
|
+
type="radio"
|
|
192
|
+
name="accountType"
|
|
193
|
+
value="business"
|
|
194
|
+
checked={accountType === "business"}
|
|
195
|
+
onChange={() => setAccountType("business")}
|
|
196
|
+
disabled={loading}
|
|
197
|
+
/>
|
|
198
|
+
Business / Brand / Company
|
|
199
|
+
</label>
|
|
200
|
+
</div>
|
|
201
|
+
</label>
|
|
202
|
+
{accountType === "business" && (
|
|
203
|
+
<label>
|
|
204
|
+
Brand / Company Name (required for business)
|
|
205
|
+
<input
|
|
206
|
+
value={companyName}
|
|
207
|
+
onChange={(e) => setCompanyName(e.target.value)}
|
|
208
|
+
disabled={loading}
|
|
209
|
+
/>
|
|
210
|
+
</label>
|
|
211
|
+
)}
|
|
212
|
+
|
|
213
|
+
{error && <div className="auth-error">{error}</div>}
|
|
214
|
+
|
|
215
|
+
<div className="form-actions">
|
|
216
|
+
<button type="button" onClick={handleBack} disabled={loading}>
|
|
217
|
+
Back
|
|
218
|
+
</button>
|
|
219
|
+
<button type="submit" disabled={loading}>
|
|
220
|
+
{loading ? "Signing up..." : "Sign up"}
|
|
221
|
+
</button>
|
|
222
|
+
</div>
|
|
223
|
+
</>
|
|
224
|
+
)}
|
|
225
|
+
</form>
|
|
226
|
+
</div>
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export default Signup;
|
package/src/Pages/Support.js
CHANGED
|
@@ -1,68 +1,68 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import HeadTags from "asggen-headtags";
|
|
3
|
-
import * as styles from "../Style/Support.module.css";
|
|
4
|
-
import MeshGradient from "../Components/Background/MeshGradient";
|
|
5
|
-
|
|
6
|
-
const Support = ({ context }) => {
|
|
7
|
-
const title = "Support - AFront";
|
|
8
|
-
const description =
|
|
9
|
-
"Get support for AFront, a front-end JavaScript library for seamless server-side rendering.";
|
|
10
|
-
const keywords = "support, AFront, server-side rendering, JavaScript";
|
|
11
|
-
HeadTags({ title, description, keywords, context });
|
|
12
|
-
|
|
13
|
-
return (
|
|
14
|
-
<MeshGradient>
|
|
15
|
-
<div className={styles.supportContainer}>
|
|
16
|
-
<h1 className={styles.supportTitle}>Need Assistance?</h1>
|
|
17
|
-
<p className={styles.supportDescription}>
|
|
18
|
-
AFront is a cutting-edge front-end JavaScript library designed for
|
|
19
|
-
seamless server-side rendering (SSR). We're committed to providing you
|
|
20
|
-
with top-notch support to ensure your experience is smooth and
|
|
21
|
-
productive.
|
|
22
|
-
</p>
|
|
23
|
-
<div className={styles.supportContent}>
|
|
24
|
-
<div className={styles.supportCard}>
|
|
25
|
-
<h2 className={styles.supportCardTitle}>Technical Assistance</h2>
|
|
26
|
-
<p className={styles.supportCardContent}>
|
|
27
|
-
Our dedicated technical support team is available around the clock
|
|
28
|
-
to resolve any issues you may face with AFront. Connect with us
|
|
29
|
-
through email or our support portal for prompt assistance.
|
|
30
|
-
</p>
|
|
31
|
-
</div>
|
|
32
|
-
<div className={styles.supportCard}>
|
|
33
|
-
<h2 className={styles.supportCardTitle}>Product Information</h2>
|
|
34
|
-
<p className={styles.supportCardContent}>
|
|
35
|
-
Curious about AFront’s capabilities? Reach out to our sales team
|
|
36
|
-
for detailed insights on features, benefits, and how our library
|
|
37
|
-
can enhance your web development projects.
|
|
38
|
-
</p>
|
|
39
|
-
</div>
|
|
40
|
-
<div className={styles.supportCard}>
|
|
41
|
-
<h2 className={styles.supportCardTitle}>Community and Forums</h2>
|
|
42
|
-
<p className={styles.supportCardContent}>
|
|
43
|
-
Join our vibrant community forums to discuss AFront with fellow
|
|
44
|
-
developers, exchange tips, and troubleshoot common issues
|
|
45
|
-
collaboratively.
|
|
46
|
-
</p>
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
|
-
<div className={styles.supportFAQ}>
|
|
50
|
-
<h2 className={styles.supportCardTitle}>
|
|
51
|
-
Frequently Asked Questions
|
|
52
|
-
</h2>
|
|
53
|
-
<ul className={styles.faqList}>
|
|
54
|
-
<li>What is AFront and how does it work?</li>
|
|
55
|
-
<li>How do I get started with AFront?</li>
|
|
56
|
-
<li>Where can I find documentation and tutorials?</li>
|
|
57
|
-
<li>How can I report a bug or request a feature?</li>
|
|
58
|
-
</ul>
|
|
59
|
-
</div>
|
|
60
|
-
<a href="/" className={styles.footerLink}>
|
|
61
|
-
Back to Homepage
|
|
62
|
-
</a>
|
|
63
|
-
</div>
|
|
64
|
-
</MeshGradient>
|
|
65
|
-
);
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export default Support;
|
|
1
|
+
import React from "react";
|
|
2
|
+
import HeadTags from "asggen-headtags";
|
|
3
|
+
import * as styles from "../Style/Support.module.css";
|
|
4
|
+
import MeshGradient from "../Components/Background/MeshGradient";
|
|
5
|
+
|
|
6
|
+
const Support = ({ context }) => {
|
|
7
|
+
const title = "Support - AFront";
|
|
8
|
+
const description =
|
|
9
|
+
"Get support for AFront, a front-end JavaScript library for seamless server-side rendering.";
|
|
10
|
+
const keywords = "support, AFront, server-side rendering, JavaScript";
|
|
11
|
+
HeadTags({ title, description, keywords, context });
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<MeshGradient>
|
|
15
|
+
<div className={styles.supportContainer}>
|
|
16
|
+
<h1 className={styles.supportTitle}>Need Assistance?</h1>
|
|
17
|
+
<p className={styles.supportDescription}>
|
|
18
|
+
AFront is a cutting-edge front-end JavaScript library designed for
|
|
19
|
+
seamless server-side rendering (SSR). We're committed to providing you
|
|
20
|
+
with top-notch support to ensure your experience is smooth and
|
|
21
|
+
productive.
|
|
22
|
+
</p>
|
|
23
|
+
<div className={styles.supportContent}>
|
|
24
|
+
<div className={styles.supportCard}>
|
|
25
|
+
<h2 className={styles.supportCardTitle}>Technical Assistance</h2>
|
|
26
|
+
<p className={styles.supportCardContent}>
|
|
27
|
+
Our dedicated technical support team is available around the clock
|
|
28
|
+
to resolve any issues you may face with AFront. Connect with us
|
|
29
|
+
through email or our support portal for prompt assistance.
|
|
30
|
+
</p>
|
|
31
|
+
</div>
|
|
32
|
+
<div className={styles.supportCard}>
|
|
33
|
+
<h2 className={styles.supportCardTitle}>Product Information</h2>
|
|
34
|
+
<p className={styles.supportCardContent}>
|
|
35
|
+
Curious about AFront’s capabilities? Reach out to our sales team
|
|
36
|
+
for detailed insights on features, benefits, and how our library
|
|
37
|
+
can enhance your web development projects.
|
|
38
|
+
</p>
|
|
39
|
+
</div>
|
|
40
|
+
<div className={styles.supportCard}>
|
|
41
|
+
<h2 className={styles.supportCardTitle}>Community and Forums</h2>
|
|
42
|
+
<p className={styles.supportCardContent}>
|
|
43
|
+
Join our vibrant community forums to discuss AFront with fellow
|
|
44
|
+
developers, exchange tips, and troubleshoot common issues
|
|
45
|
+
collaboratively.
|
|
46
|
+
</p>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
<div className={styles.supportFAQ}>
|
|
50
|
+
<h2 className={styles.supportCardTitle}>
|
|
51
|
+
Frequently Asked Questions
|
|
52
|
+
</h2>
|
|
53
|
+
<ul className={styles.faqList}>
|
|
54
|
+
<li>What is AFront and how does it work?</li>
|
|
55
|
+
<li>How do I get started with AFront?</li>
|
|
56
|
+
<li>Where can I find documentation and tutorials?</li>
|
|
57
|
+
<li>How can I report a bug or request a feature?</li>
|
|
58
|
+
</ul>
|
|
59
|
+
</div>
|
|
60
|
+
<a href="/" className={styles.footerLink}>
|
|
61
|
+
Back to Homepage
|
|
62
|
+
</a>
|
|
63
|
+
</div>
|
|
64
|
+
</MeshGradient>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export default Support;
|