l-min-components 1.0.747 → 1.0.753
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/package.json +2 -1
- package/src/assets/images/koreaFlag.png +0 -0
- package/src/components/AppMainLayout/index.jsx +144 -128
- package/src/components/header/index.jsx +24 -30
- package/src/components/header/index.styled.js +5 -0
- package/src/components/header/languageDropdown.jsx +38 -13
- package/src/components/header/login-header.jsx +29 -5
- package/src/hooks/useTranslation.jsx +24 -0
- package/src/hooks/utils/translation.js +65 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "l-min-components",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.753",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"src/assets",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"lottie-web": "^5.12.2",
|
|
25
25
|
"moment": "^2.29.4",
|
|
26
26
|
"npm": "^10.2.5",
|
|
27
|
+
"papaparse": "^5.4.1",
|
|
27
28
|
"prop-types": "^15.8.1",
|
|
28
29
|
"rc-pagination": "^4.0.4",
|
|
29
30
|
"rc-progress": "^3.5.1",
|
|
Binary file
|
|
@@ -28,6 +28,7 @@ import PersonalRightBar from "../fileRightBar/personalRightBar";
|
|
|
28
28
|
import useHeader from "../header/getHeaderDetails";
|
|
29
29
|
import GracePeriod from "../deactivated";
|
|
30
30
|
import MobileLayout from "../mobileLayout";
|
|
31
|
+
import useTranslation from "../../hooks/useTranslation";
|
|
31
32
|
|
|
32
33
|
const AppMainLayout = () => {
|
|
33
34
|
const [isOpen, setIsOpen] = useState(true);
|
|
@@ -152,141 +153,156 @@ const AppMainLayout = () => {
|
|
|
152
153
|
const currentPlan = userPlanData?.data?.current_plan;
|
|
153
154
|
const planState = userPlanData?.data?.state;
|
|
154
155
|
|
|
156
|
+
const { textSchema, setDefaultLang, findText } = useTranslation();
|
|
157
|
+
// console.log(findText());
|
|
155
158
|
return (
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
) : (
|
|
191
|
-
<Layout
|
|
192
|
-
coming={coming}
|
|
193
|
-
hasLayoutBackgroundImage={hasLayoutBackgroundImage}
|
|
159
|
+
textSchema && (
|
|
160
|
+
<OutletContext.Provider
|
|
161
|
+
value={{
|
|
162
|
+
textSchema,
|
|
163
|
+
findText,
|
|
164
|
+
setDefaultLang,
|
|
165
|
+
setRightComponent,
|
|
166
|
+
setRightLayout,
|
|
167
|
+
generalData,
|
|
168
|
+
setGeneralData,
|
|
169
|
+
coming,
|
|
170
|
+
hasLayoutBackgroundImage,
|
|
171
|
+
setHasLayoutBackgroundImage,
|
|
172
|
+
setSideMenuLayout,
|
|
173
|
+
activePage,
|
|
174
|
+
setActivePage,
|
|
175
|
+
studyTab,
|
|
176
|
+
setStudyTab,
|
|
177
|
+
page,
|
|
178
|
+
setPage,
|
|
179
|
+
selectedCourseId,
|
|
180
|
+
setSelectedCourseId,
|
|
181
|
+
centerLayoutStyle,
|
|
182
|
+
setCenterLayoutStyle,
|
|
183
|
+
// return true if instructor affiliates is Active
|
|
184
|
+
setHideAffilicates,
|
|
185
|
+
affiliatesActive,
|
|
186
|
+
accessToken,
|
|
187
|
+
envType,
|
|
188
|
+
newNotifications,
|
|
189
|
+
setNewNotifications,
|
|
190
|
+
notificationMarkReadData,
|
|
191
|
+
handleGetNotificationMarkRead,
|
|
192
|
+
}}
|
|
194
193
|
>
|
|
195
|
-
|
|
196
|
-
<
|
|
197
|
-
<
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
194
|
+
{/* display mobile layout on device width*/}
|
|
195
|
+
{deviceWidth < 1200 ? (
|
|
196
|
+
<MobileLayout />
|
|
197
|
+
) : (
|
|
198
|
+
<Layout
|
|
199
|
+
coming={coming}
|
|
200
|
+
hasLayoutBackgroundImage={hasLayoutBackgroundImage}
|
|
201
|
+
>
|
|
202
|
+
<HeaderComponent setNewNotifications={setNewNotifications} />
|
|
203
|
+
<MainLayout coming={coming}>
|
|
204
|
+
<LeftLayout>
|
|
205
|
+
<SideBar routes={leftNavMenu} />
|
|
206
|
+
{!coming && (
|
|
207
|
+
<>
|
|
208
|
+
{sideMenuLayout && (
|
|
209
|
+
<SideMenu
|
|
210
|
+
user={user}
|
|
211
|
+
routes={sideMenuOptions}
|
|
212
|
+
affiliatesActive={affiliatesActive}
|
|
213
|
+
userType={generalData?.selectedAccount?.type?.toLowerCase()}
|
|
214
|
+
isOpen={isOpen}
|
|
215
|
+
setIsOpen={setIsOpen}
|
|
216
|
+
setRightComponent={setRightComponent}
|
|
217
|
+
planState={planState}
|
|
218
|
+
/>
|
|
219
|
+
)}
|
|
220
|
+
</>
|
|
212
221
|
)}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
/>
|
|
236
|
-
)}
|
|
237
|
-
|
|
238
|
-
{window.location.pathname.includes("enterprise") &&
|
|
239
|
-
planState === "GRACE PERIOD" ? (
|
|
240
|
-
<GracePeriod
|
|
241
|
-
getCurrentSubscriptionData={getCurrentSubscriptionData}
|
|
242
|
-
handleCurrentSubscription={handleCurrentSubscription}
|
|
243
|
-
gracePeriod={gracePeriod}
|
|
244
|
-
/>
|
|
245
|
-
) : (
|
|
246
|
-
<Outlet />
|
|
247
|
-
)}
|
|
248
|
-
</CenterLayout>
|
|
222
|
+
{
|
|
223
|
+
// window.location.pathname.includes("enterprise")
|
|
224
|
+
// ? "enterprise"
|
|
225
|
+
// : window.location.pathname.includes("personal")
|
|
226
|
+
// ? "personal"
|
|
227
|
+
// : window.location.pathname.includes("instructor")
|
|
228
|
+
// ? "instructor"
|
|
229
|
+
// : window.location.pathname.includes("developer") ||
|
|
230
|
+
// window.location.hostname.includes("developer")
|
|
231
|
+
// ? "developer"
|
|
232
|
+
// : "developer"
|
|
233
|
+
}
|
|
234
|
+
</LeftLayout>
|
|
235
|
+
<CenterLayout isOpen={isOpen} style={centerLayoutStyle}>
|
|
236
|
+
{window.location.pathname.includes("instructor") &&
|
|
237
|
+
!window.location.pathname.includes("enterprise") &&
|
|
238
|
+
!window.location.pathname.includes("manage-teams") &&
|
|
239
|
+
!hideAffilicates && (
|
|
240
|
+
<InstructorAccountSwitcher
|
|
241
|
+
setAccountType={setAffiliatesActive}
|
|
242
|
+
/>
|
|
243
|
+
)}
|
|
249
244
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
<EnterpriseRightBar
|
|
245
|
+
{window.location.pathname.includes("enterprise") &&
|
|
246
|
+
planState === "GRACE PERIOD" ? (
|
|
247
|
+
<GracePeriod
|
|
248
|
+
getCurrentSubscriptionData={getCurrentSubscriptionData}
|
|
249
|
+
handleCurrentSubscription={handleCurrentSubscription}
|
|
256
250
|
gracePeriod={gracePeriod}
|
|
257
|
-
setGracePeriod={setGracePeriod}
|
|
258
|
-
planState={planState}
|
|
259
251
|
/>
|
|
260
|
-
) : window.location.pathname.includes("personal/dashboard") ? (
|
|
261
|
-
<PersonalRightBar />
|
|
262
|
-
) : window.location.pathname.includes("personal/addons") ? (
|
|
263
|
-
<InstructorRightBar personal />
|
|
264
|
-
) : window.location.pathname.includes("personal/courses") ? (
|
|
265
|
-
<InstructorRightBar personal />
|
|
266
|
-
) : window.location.pathname.includes(
|
|
267
|
-
"personal/library/selectlanguage",
|
|
268
|
-
) ? (
|
|
269
|
-
<InstructorRightBar personal />
|
|
270
|
-
) : window.location.pathname.includes("personal/library") ? (
|
|
271
|
-
<PersonalRightBar personalLibrary />
|
|
272
|
-
) : window.location.pathname.includes("personal/reports") ? (
|
|
273
|
-
<PersonalRightBar personalReport />
|
|
274
|
-
) : window.location.pathname.includes("instructor") &&
|
|
275
|
-
!window.location.pathname.includes("manage-teams") &&
|
|
276
|
-
!window.location.pathname.includes("file-manager") ? (
|
|
277
|
-
<InstructorRightBar />
|
|
278
|
-
) : window.location.pathname.includes("developer") ? (
|
|
279
|
-
<Banner />
|
|
280
252
|
) : (
|
|
281
|
-
<
|
|
282
|
-
)
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
253
|
+
<Outlet />
|
|
254
|
+
)}
|
|
255
|
+
</CenterLayout>
|
|
256
|
+
|
|
257
|
+
{rightLayout && !coming && (
|
|
258
|
+
<RightLayout>
|
|
259
|
+
{rightComponent ??
|
|
260
|
+
(window.location.pathname.includes("enterprise") &&
|
|
261
|
+
!window.location.pathname.includes("file-manager") ? (
|
|
262
|
+
<EnterpriseRightBar
|
|
263
|
+
gracePeriod={gracePeriod}
|
|
264
|
+
setGracePeriod={setGracePeriod}
|
|
265
|
+
planState={planState}
|
|
266
|
+
/>
|
|
267
|
+
) : window.location.pathname.includes(
|
|
268
|
+
"personal/dashboard"
|
|
269
|
+
) ? (
|
|
270
|
+
<PersonalRightBar />
|
|
271
|
+
) : window.location.pathname.includes("personal/addons") ? (
|
|
272
|
+
<InstructorRightBar personal />
|
|
273
|
+
) : window.location.pathname.includes(
|
|
274
|
+
"personal/courses"
|
|
275
|
+
) ? (
|
|
276
|
+
<InstructorRightBar personal />
|
|
277
|
+
) : window.location.pathname.includes(
|
|
278
|
+
"personal/library/selectlanguage"
|
|
279
|
+
) ? (
|
|
280
|
+
<InstructorRightBar personal />
|
|
281
|
+
) : window.location.pathname.includes(
|
|
282
|
+
"personal/library"
|
|
283
|
+
) ? (
|
|
284
|
+
<PersonalRightBar personalLibrary />
|
|
285
|
+
) : window.location.pathname.includes(
|
|
286
|
+
"personal/reports"
|
|
287
|
+
) ? (
|
|
288
|
+
<PersonalRightBar personalReport />
|
|
289
|
+
) : window.location.pathname.includes("instructor") &&
|
|
290
|
+
!window.location.pathname.includes("manage-teams") &&
|
|
291
|
+
!window.location.pathname.includes("file-manager") ? (
|
|
292
|
+
<InstructorRightBar />
|
|
293
|
+
) : window.location.pathname.includes("developer") ? (
|
|
294
|
+
<Banner />
|
|
295
|
+
) : (
|
|
296
|
+
<Banner />
|
|
297
|
+
))}
|
|
298
|
+
{/* {rightComponent ?? <Banner />} */}
|
|
299
|
+
</RightLayout>
|
|
300
|
+
)}
|
|
301
|
+
</MainLayout>
|
|
302
|
+
</Layout>
|
|
303
|
+
)}
|
|
304
|
+
</OutletContext.Provider>
|
|
305
|
+
)
|
|
290
306
|
);
|
|
291
307
|
};
|
|
292
308
|
|
|
@@ -61,7 +61,7 @@ const HeaderComponent = (props) => {
|
|
|
61
61
|
handleGetNotification,
|
|
62
62
|
} = useHeader();
|
|
63
63
|
const { pathname } = useLocation();
|
|
64
|
-
const { setGeneralData, generalData, notificationMarkReadData } =
|
|
64
|
+
const { setGeneralData, generalData, notificationMarkReadData, findText } =
|
|
65
65
|
useContext(OutletContext);
|
|
66
66
|
const [selectedAccount, setSelectedAccount] = useState();
|
|
67
67
|
const { setDefaultAccount, handleSetDefaultAccount } = useHeader();
|
|
@@ -158,25 +158,25 @@ const HeaderComponent = (props) => {
|
|
|
158
158
|
// Checking for delete account
|
|
159
159
|
useEffect(() => {
|
|
160
160
|
if (userAccountsDetail?.data) {
|
|
161
|
-
const validAccounts = userAccountsDetail.data.results.filter(
|
|
161
|
+
const validAccounts = userAccountsDetail.data.results.filter(
|
|
162
|
+
(account) => !account.pending_delete
|
|
163
|
+
);
|
|
162
164
|
|
|
163
|
-
if (
|
|
164
|
-
|
|
165
|
+
if (
|
|
166
|
+
generalData?.selectedAccount &&
|
|
167
|
+
generalData?.selectedAccount?.pending_delete
|
|
168
|
+
) {
|
|
169
|
+
const nextValidAccount = validAccounts[0];
|
|
165
170
|
if (nextValidAccount) {
|
|
166
171
|
setSelectedAccount(nextValidAccount);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
172
|
+
} else {
|
|
173
|
+
// Fallback to personal account or some default setting
|
|
174
|
+
setSelectedAccount(personalAccountData[0]);
|
|
175
|
+
}
|
|
171
176
|
}
|
|
172
|
-
|
|
173
177
|
}
|
|
174
|
-
}, [
|
|
175
|
-
generalData?.selectedAccount,
|
|
176
|
-
userAccountsDetail?.data,
|
|
178
|
+
}, [generalData?.selectedAccount, userAccountsDetail?.data]);
|
|
177
179
|
|
|
178
|
-
]);
|
|
179
|
-
|
|
180
180
|
const containerRef = useRef(null);
|
|
181
181
|
const secondContainerRef = useRef(null);
|
|
182
182
|
const acctDropdownContainerRef = useRef(null);
|
|
@@ -266,7 +266,7 @@ const HeaderComponent = (props) => {
|
|
|
266
266
|
if (path.includes("duet")) return "Duet";
|
|
267
267
|
if (path.includes("speech")) return "Speech";
|
|
268
268
|
if (path.includes("dictionary")) return "Dictionary";
|
|
269
|
-
return "Learning";
|
|
269
|
+
return findText("Learning");
|
|
270
270
|
};
|
|
271
271
|
|
|
272
272
|
// websocket for notifications initialization
|
|
@@ -371,8 +371,7 @@ const HeaderComponent = (props) => {
|
|
|
371
371
|
onClick={() => {
|
|
372
372
|
setLanguageDropdown();
|
|
373
373
|
setIsOpen();
|
|
374
|
-
}}
|
|
375
|
-
>
|
|
374
|
+
}}>
|
|
376
375
|
<li>
|
|
377
376
|
<a className={isHomePage() ? "active" : ""}>
|
|
378
377
|
<BookIcon /> {getNavLinkLabel()}
|
|
@@ -397,9 +396,8 @@ const HeaderComponent = (props) => {
|
|
|
397
396
|
className={
|
|
398
397
|
window.location.pathname.includes("settings") ? "active" : ""
|
|
399
398
|
}
|
|
400
|
-
style={{ cursor: "pointer" }}
|
|
401
|
-
|
|
402
|
-
<SettingIcon /> Settings
|
|
399
|
+
style={{ cursor: "pointer" }}>
|
|
400
|
+
<SettingIcon /> {findText("Settings")}
|
|
403
401
|
</a>
|
|
404
402
|
</li>
|
|
405
403
|
<li>
|
|
@@ -412,14 +410,13 @@ const HeaderComponent = (props) => {
|
|
|
412
410
|
className={
|
|
413
411
|
window.location.pathname.includes("notifications") ? "active" : ""
|
|
414
412
|
}
|
|
415
|
-
style={{ cursor: "pointer" }}
|
|
416
|
-
>
|
|
413
|
+
style={{ cursor: "pointer" }}>
|
|
417
414
|
{unreadNotificationData?.data?.count > 0 ? (
|
|
418
415
|
<NotificationIcon />
|
|
419
416
|
) : (
|
|
420
417
|
<NotificationEmptyIcon />
|
|
421
418
|
)}
|
|
422
|
-
Notifications
|
|
419
|
+
{findText("Notifications")}
|
|
423
420
|
</a>
|
|
424
421
|
</li>
|
|
425
422
|
</Nav>
|
|
@@ -428,8 +425,7 @@ const HeaderComponent = (props) => {
|
|
|
428
425
|
onClick={() => {
|
|
429
426
|
setLanguageDropdown();
|
|
430
427
|
setIsOpen();
|
|
431
|
-
}}
|
|
432
|
-
>
|
|
428
|
+
}}>
|
|
433
429
|
<SearchInputGroup>
|
|
434
430
|
<SearchIcon />
|
|
435
431
|
<SearchInput
|
|
@@ -446,7 +442,7 @@ const HeaderComponent = (props) => {
|
|
|
446
442
|
{searchResultOpen && (
|
|
447
443
|
<div className="search-result-wrapper">
|
|
448
444
|
<p>
|
|
449
|
-
Website <span>UIUX </span> Design
|
|
445
|
+
{/* Website <span>UIUX </span> Design */}
|
|
450
446
|
</p>
|
|
451
447
|
</div>
|
|
452
448
|
)}
|
|
@@ -458,8 +454,7 @@ const HeaderComponent = (props) => {
|
|
|
458
454
|
onClick={() => {
|
|
459
455
|
setLanguageDropdown(!languageDropdown);
|
|
460
456
|
setIsOpen();
|
|
461
|
-
}}
|
|
462
|
-
>
|
|
457
|
+
}}>
|
|
463
458
|
<img src={usFlag} alt="" />
|
|
464
459
|
<ArrowDownIcon />
|
|
465
460
|
</div>
|
|
@@ -477,8 +472,7 @@ const HeaderComponent = (props) => {
|
|
|
477
472
|
setIsOpen(!isOpen);
|
|
478
473
|
setLanguageDropdown();
|
|
479
474
|
}}
|
|
480
|
-
ref={secondContainerRef}
|
|
481
|
-
>
|
|
475
|
+
ref={secondContainerRef}>
|
|
482
476
|
<div className="user-img-container">
|
|
483
477
|
<img
|
|
484
478
|
src={selectedAccount?.profile_photo?.url || avatar}
|
|
@@ -4,6 +4,7 @@ import useHeader from "./getHeaderDetails";
|
|
|
4
4
|
import { OutletContext } from "..";
|
|
5
5
|
import { useLocation } from "react-router-dom";
|
|
6
6
|
import usFlag from "../../assets/images/usFlag.png";
|
|
7
|
+
import koreanFlag from "../../assets/images/koreaFlag.png";
|
|
7
8
|
import { LanguageDropdownContainer } from "./index.styled";
|
|
8
9
|
import { RiCloseCircleFill } from "react-icons/ri";
|
|
9
10
|
import { HiSearch } from "react-icons/hi";
|
|
@@ -20,7 +21,8 @@ import { DebounceInput } from "react-debounce-input";
|
|
|
20
21
|
*
|
|
21
22
|
*/
|
|
22
23
|
const LanguageDropdown = ({ languageDropdown, setLanguageDropdown }) => {
|
|
23
|
-
const { setGeneralData, generalData } =
|
|
24
|
+
const { setGeneralData, generalData, setDefaultLang, findText } =
|
|
25
|
+
useContext(OutletContext);
|
|
24
26
|
const [filteredData, setFilteredData] = useState([]);
|
|
25
27
|
const [isSearch, setIsSearch] = useState(false);
|
|
26
28
|
const containerRef = useRef(null);
|
|
@@ -29,8 +31,8 @@ const LanguageDropdown = ({ languageDropdown, setLanguageDropdown }) => {
|
|
|
29
31
|
|
|
30
32
|
const handleFilter = (event) => {
|
|
31
33
|
const searchWord = event.target.value;
|
|
32
|
-
const newFilter =
|
|
33
|
-
return item?.toLowerCase().includes(searchWord.toLowerCase());
|
|
34
|
+
const newFilter = languagesData.filter((item) => {
|
|
35
|
+
return item?.name?.toLowerCase().includes(searchWord.toLowerCase());
|
|
34
36
|
});
|
|
35
37
|
console.log("newFilter", newFilter);
|
|
36
38
|
if (searchWord === "") {
|
|
@@ -60,10 +62,23 @@ const LanguageDropdown = ({ languageDropdown, setLanguageDropdown }) => {
|
|
|
60
62
|
};
|
|
61
63
|
}, [setLanguageDropdown]);
|
|
62
64
|
|
|
65
|
+
const languagesData = [
|
|
66
|
+
{
|
|
67
|
+
name: "English",
|
|
68
|
+
flag: usFlag,
|
|
69
|
+
slug: "en",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "Korean",
|
|
73
|
+
flag: koreanFlag,
|
|
74
|
+
slug: "ko",
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
|
|
63
78
|
return (
|
|
64
79
|
<LanguageDropdownContainer ref={containerRef}>
|
|
65
80
|
<div className="ldc_header">
|
|
66
|
-
<p className="ldc_title"> Whats your language</p>
|
|
81
|
+
<p className="ldc_title"> {findText("Whats your language")}</p>
|
|
67
82
|
<span onClick={() => setLanguageDropdown(false)}>
|
|
68
83
|
<RiCloseCircleFill />
|
|
69
84
|
</span>
|
|
@@ -91,21 +106,31 @@ const LanguageDropdown = ({ languageDropdown, setLanguageDropdown }) => {
|
|
|
91
106
|
filteredData?.map((item, index) => (
|
|
92
107
|
<p
|
|
93
108
|
className="language_dropdown_item"
|
|
94
|
-
onClick={() =>
|
|
109
|
+
onClick={() => {
|
|
110
|
+
setLanguageDropdown();
|
|
111
|
+
setDefaultLang(item?.slug);
|
|
112
|
+
localStorage.setItem("defaultLang", item?.slug);
|
|
113
|
+
}}
|
|
95
114
|
>
|
|
96
|
-
<img src={
|
|
115
|
+
<img src={item?.flag} alt="" /> <span>{item?.name}</span>
|
|
97
116
|
</p>
|
|
98
117
|
))}
|
|
99
118
|
|
|
100
119
|
{!isSearch && (
|
|
101
120
|
<>
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
121
|
+
{languagesData?.map((item, idx) => (
|
|
122
|
+
<p
|
|
123
|
+
className="language_dropdown_item"
|
|
124
|
+
onClick={() => {
|
|
125
|
+
setLanguageDropdown();
|
|
126
|
+
setDefaultLang(item?.slug);
|
|
127
|
+
localStorage.setItem("defaultLang", item?.slug);
|
|
128
|
+
}}
|
|
129
|
+
>
|
|
130
|
+
<img src={item?.flag} alt="" />{" "}
|
|
131
|
+
<span>{findText(`${item?.name}`)}</span>
|
|
132
|
+
</p>
|
|
133
|
+
))}
|
|
109
134
|
</>
|
|
110
135
|
)}
|
|
111
136
|
</div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useEffect, useRef, useCallback } from "react";
|
|
1
|
+
import React, { useState, useEffect, useRef, useCallback, useContext } from "react";
|
|
2
2
|
import ReactFlagsSelect from "react-flags-select";
|
|
3
3
|
import logo from "./assets/images/logo.png";
|
|
4
4
|
import { Navbar2, NavGroup2, Nav2, CountryFlagGroup2 } from "./index.styled";
|
|
@@ -6,6 +6,7 @@ import { ArrowDownIcon } from "./assets/svg/arrow-down";
|
|
|
6
6
|
import ButtonComponent from "../button";
|
|
7
7
|
import { useLocation, useNavigate } from "react-router-dom";
|
|
8
8
|
import usFlag from "../../assets/images/usFlag.png";
|
|
9
|
+
import { OutletContext } from "..";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* @param {{
|
|
@@ -17,6 +18,8 @@ import usFlag from "../../assets/images/usFlag.png";
|
|
|
17
18
|
*
|
|
18
19
|
*/
|
|
19
20
|
const HeaderComponentTwo = (props) => {
|
|
21
|
+
const { setGeneralData, generalData, setDefaultLang, findText } =
|
|
22
|
+
useContext(OutletContext);
|
|
20
23
|
const [selected, setSelected] = useState("ES");
|
|
21
24
|
const [isOpen, setIsOpen] = useState(false);
|
|
22
25
|
const [searchResultOpen, setSearchResultOpen] = useState(false);
|
|
@@ -38,7 +41,7 @@ const HeaderComponentTwo = (props) => {
|
|
|
38
41
|
const containerRef = useRef(null);
|
|
39
42
|
|
|
40
43
|
const handleLogoClick = () => {
|
|
41
|
-
window.location.href =
|
|
44
|
+
window.location.href = "https://learngual.com/";
|
|
42
45
|
};
|
|
43
46
|
|
|
44
47
|
useEffect(() => {
|
|
@@ -57,6 +60,19 @@ const HeaderComponentTwo = (props) => {
|
|
|
57
60
|
document.removeEventListener("click", handleClickOutside);
|
|
58
61
|
};
|
|
59
62
|
}, [setLanguageDropdown]);
|
|
63
|
+
|
|
64
|
+
const languagesData = [
|
|
65
|
+
{
|
|
66
|
+
name: "English",
|
|
67
|
+
flag: usFlag,
|
|
68
|
+
slug: "en",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: "Korean",
|
|
72
|
+
flag: koreanFlag,
|
|
73
|
+
slug: "ko",
|
|
74
|
+
},
|
|
75
|
+
];
|
|
60
76
|
return (
|
|
61
77
|
<Navbar2
|
|
62
78
|
onClick={() => {
|
|
@@ -92,9 +108,17 @@ const HeaderComponentTwo = (props) => {
|
|
|
92
108
|
</div>
|
|
93
109
|
{languageDropdown && (
|
|
94
110
|
<ul className="dropdown_list" ref={containerRef}>
|
|
95
|
-
|
|
96
|
-
<
|
|
97
|
-
|
|
111
|
+
{languagesData?.map((item, idx) => (
|
|
112
|
+
<li
|
|
113
|
+
onClick={() => {
|
|
114
|
+
setLanguageDropdown();
|
|
115
|
+
setDefaultLang(item?.slug);
|
|
116
|
+
localStorage.setItem("defaultLang", item?.slug);
|
|
117
|
+
}}
|
|
118
|
+
>
|
|
119
|
+
<img src={item?.flag} alt="" /> <span>{item?.name}</span>
|
|
120
|
+
</li>
|
|
121
|
+
))}
|
|
98
122
|
</ul>
|
|
99
123
|
)}
|
|
100
124
|
</div>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from "react";
|
|
2
|
+
import loadTranslations from "./utils/translation";
|
|
3
|
+
|
|
4
|
+
const useTranslation = () => {
|
|
5
|
+
const value = localStorage.getItem("defaultLang");
|
|
6
|
+
const [textSchema, setTextSchema] = useState(null);
|
|
7
|
+
|
|
8
|
+
const [defaultLang, setDefaultLang] = useState(value || "en");
|
|
9
|
+
const findText = useCallback((str) => textSchema[str] ?? str, [textSchema]);
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
loadTranslations(undefined, defaultLang).then((res) => setTextSchema(res));
|
|
13
|
+
}, [defaultLang]);
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
textSchema,
|
|
17
|
+
setTextSchema,
|
|
18
|
+
setDefaultLang,
|
|
19
|
+
defaultLang,
|
|
20
|
+
findText,
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default useTranslation;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// import Tabletop from "tabletop";
|
|
2
|
+
import Papa from "papaparse";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Loads translation data from a Google Sheet URL into a structured object.
|
|
6
|
+
*
|
|
7
|
+
* @param {string} sheetUrl - The URL of the published Google Sheet.
|
|
8
|
+
* @param {string[]} languages - Array of language codes (e.g., ['es', 'fr']) to include in the result.
|
|
9
|
+
* @returns {Promise<Object>} A Promise that resolves to an object with English keys and translated values.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const protoUrl =
|
|
13
|
+
"https://docs.google.com/spreadsheets/d/e/2PACX-1vSvUIA_1eqpANaRTXafwYkh0y7ZYfbgvlHeLNjti21yjdtJjy6Fjk7pAuQjODROqT3uALC2Aq_odZy4/pub?gid=0&single=true&output=csv";
|
|
14
|
+
|
|
15
|
+
async function loadTranslations(sheetUrl = protoUrl, language = "") {
|
|
16
|
+
try {
|
|
17
|
+
// 1. Fetch data from the Google Sheet
|
|
18
|
+
const response = await fetch(sheetUrl);
|
|
19
|
+
|
|
20
|
+
// Check if the request was successful
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`Failed to fetch from Google Sheet: ${response.status} ${response.statusText}`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const csvData = await response.text();
|
|
28
|
+
|
|
29
|
+
// 2. Parse CSV data (handling quoted fields with commas)
|
|
30
|
+
const parseResult = Papa.parse(csvData, { header: true });
|
|
31
|
+
|
|
32
|
+
// Check for parsing errors
|
|
33
|
+
if (parseResult.errors.length > 0) {
|
|
34
|
+
throw new Error(`Failed to parse CSV data: ${parseResult.errors}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const rows = parseResult.data;
|
|
38
|
+
|
|
39
|
+
// 3. Identify the English column and language columns
|
|
40
|
+
const headers = Object.keys(rows[0]);
|
|
41
|
+
|
|
42
|
+
const englishColumnIndex = headers.indexOf("en"); // Using 'en' instead of 'English' based on your feedback
|
|
43
|
+
|
|
44
|
+
// Ensure English column exists
|
|
45
|
+
if (englishColumnIndex === -1) {
|
|
46
|
+
throw new Error("English column not found in Google Sheet");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// if language exists
|
|
50
|
+
if (!headers.includes(language))
|
|
51
|
+
throw new Error(language.concat(" translation not found"));
|
|
52
|
+
|
|
53
|
+
const translations = {};
|
|
54
|
+
for (let row of rows) {
|
|
55
|
+
translations[row.en.trim().replace(/\r\n|\r/g, "\n")] = row[language];
|
|
56
|
+
}
|
|
57
|
+
return translations;
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error("Error loading translations:", error);
|
|
60
|
+
return {};
|
|
61
|
+
// throw error; // Rethrow for handling elsewhere
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default loadTranslations;
|