Skip to content

Commit 0039e3c

Browse files
authored
Merge pull request #2989 from tekdi/release-1.16.0
Release 1.16.0 to learner qa
2 parents 7548082 + 576aa9f commit 0039e3c

8 files changed

Lines changed: 1350 additions & 1 deletion

File tree

apps/learner-web-app/src/app/[programName]/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import Header from '@learner/components/Header/Header';
1313
import { getTenantInfo } from '@learner/utils/API/ProgramService';
1414
import { useTranslation } from '@shared-lib';
1515
import EnrolModal from '@learner/components/EnrolModal/EnrolModal';
16+
import LanguageSelectionPopup from '@learner/components/LanguageSelectionPopup/LanguageSelectionPopup';
1617
import DOMPurify from 'dompurify';
1718

1819
interface Program {
@@ -132,6 +133,7 @@ export default function ProgramDetailPage() {
132133

133134
return (
134135
<>
136+
<LanguageSelectionPopup />
135137
<Header />
136138

137139
<Box sx={{ backgroundColor: '#fff', minHeight: '100vh' }}>

apps/learner-web-app/src/app/landing/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import MenuBookOutlinedIcon from '@mui/icons-material/MenuBookOutlined';
1212
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
1313
import RoleCard, { ROLE_CARD_THEMES } from '@learner/components/RoleCard/RoleCard';
1414
import ProgramCard from '@learner/components/ProgramCard/ProgramCard';
15+
import LanguageSelectionPopup from '@learner/components/LanguageSelectionPopup/LanguageSelectionPopup';
1516

1617
interface Program {
1718
ordering: number;
@@ -132,6 +133,7 @@ export default function LandingPage() {
132133

133134
return (
134135
<>
136+
<LanguageSelectionPopup />
135137
<Header isLogin={true}/>
136138
<Box
137139
sx={{

apps/learner-web-app/src/app/login/page.tsx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -853,7 +853,26 @@ const LoginPageContent = () => {
853853
primaryText={t('LANDING.ENROL_NOW') || 'Enrol Now'}
854854
primaryActionHandler={() => {
855855
setNotEnrolledModal(false);
856-
router.push(`/${encodeURIComponent(notEnrolledProgramName)}`);
856+
const currentTenantId = localStorage.getItem('tenantId');
857+
localStorage.setItem('previousTenantId', currentTenantId || '');
858+
localStorage.setItem('tenantId', notEnrolledTenantId);
859+
localStorage.setItem('userProgram', notEnrolledProgramName);
860+
localStorage.setItem('onboardTenantId', notEnrolledTenantId);
861+
if (enrollConfirmProgramData?.params?.uiConfig) {
862+
localStorage.setItem('uiConfig', JSON.stringify(enrollConfirmProgramData.params.uiConfig));
863+
}
864+
if (enrollConfirmProgramData?.params?.uiConfig?.landingPage) {
865+
localStorage.setItem('landingPage', enrollConfirmProgramData.params.uiConfig.landingPage);
866+
}
867+
localStorage.setItem('enrolledProgramData', JSON.stringify({
868+
tenantId: notEnrolledTenantId,
869+
name: notEnrolledProgramName,
870+
params: enrollConfirmProgramData?.params || {},
871+
}));
872+
if (enrollConfirmProgramData?.type) {
873+
localStorage.setItem('temp_program_type', enrollConfirmProgramData.type);
874+
}
875+
router.push('/enroll-profile-completion');
857876
}}
858877
// secondaryText={t('LEARNER_APP.PROGRAMS.MY_PROGRAMS') || 'My Programs'}
859878
// secondaryActionHandler={() => { setNotEnrolledModal(false); router.push('/programs'); }}

apps/learner-web-app/src/components/Header/Header.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ const Header = ({ isShowLogout = false, isLogin = false }) => {
169169
<MenuItem value="kan">ಕನ್ನಡ</MenuItem>
170170
<MenuItem value="tam">தமிழ்</MenuItem>
171171
<MenuItem value="guj">ગુજરાતી</MenuItem>
172+
<MenuItem value="ur">اردو</MenuItem>
172173
{/* Add more languages as needed */}
173174
</Select>
174175
</Box>
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
'use client';
2+
3+
import React, { useEffect, useState } from 'react';
4+
import {
5+
Box,
6+
Dialog,
7+
Typography,
8+
Grid,
9+
ButtonBase,
10+
} from '@mui/material';
11+
import type { DialogProps } from '@mui/material/Dialog';
12+
import LanguageIcon from '@mui/icons-material/Language';
13+
import { useTranslation } from '@shared-lib';
14+
import {
15+
PLP_LANGUAGE_OPTIONS,
16+
PLP_LANGUAGE_POPUP_DISMISSED_KEY,
17+
} from './languageOptions';
18+
19+
export type LanguageSelectionPopupSize = NonNullable<DialogProps['maxWidth']>;
20+
21+
interface LanguageSelectionPopupProps {
22+
/** MUI Dialog maxWidth — xs (444px), sm (600px), md (900px), etc. */
23+
size?: LanguageSelectionPopupSize;
24+
}
25+
26+
const LanguageSelectionPopup: React.FC<LanguageSelectionPopupProps> = ({
27+
size = 'xs',
28+
}) => {
29+
const { setLanguage } = useTranslation();
30+
const [open, setOpen] = useState(false);
31+
32+
useEffect(() => {
33+
if (typeof window === 'undefined') return;
34+
const dismissed = sessionStorage.getItem(PLP_LANGUAGE_POPUP_DISMISSED_KEY);
35+
if (!dismissed) {
36+
setOpen(true);
37+
}
38+
}, []);
39+
40+
const persistLanguage = (code: string) => {
41+
setLanguage(code);
42+
localStorage.setItem('lang', code);
43+
localStorage.setItem('preferredLanguage', code);
44+
45+
if (localStorage.getItem('isAndroidApp') === 'yes' && window.ReactNativeWebView) {
46+
window.ReactNativeWebView.postMessage(
47+
JSON.stringify({
48+
type: 'LANGUAGE_CHANGE_EVENT',
49+
data: { language: code },
50+
})
51+
);
52+
}
53+
};
54+
55+
const handleLanguageSelect = (code: string) => {
56+
persistLanguage(code);
57+
sessionStorage.setItem(PLP_LANGUAGE_POPUP_DISMISSED_KEY, 'true');
58+
setOpen(false);
59+
};
60+
61+
return (
62+
<Dialog
63+
open={open}
64+
maxWidth={size}
65+
fullWidth
66+
onClose={(_, reason) => {
67+
if (reason === 'backdropClick' || reason === 'escapeKeyDown') {
68+
return;
69+
}
70+
}}
71+
aria-labelledby="language-selection-title"
72+
aria-describedby="language-selection-description"
73+
slotProps={{
74+
backdrop: {
75+
sx: {
76+
backgroundColor: 'rgba(0, 0, 0, 0.45)',
77+
backdropFilter: 'blur(4px)',
78+
},
79+
},
80+
}}
81+
PaperProps={{
82+
sx: {
83+
borderRadius: '16px',
84+
boxShadow: '0px 8px 32px rgba(0, 0, 0, 0.12)',
85+
m: { xs: 2, sm: 3 },
86+
},
87+
}}
88+
>
89+
<Box sx={{ p: { xs: 2.5, sm: 3 } }}>
90+
<Box
91+
sx={{
92+
display: 'flex',
93+
flexDirection: 'column',
94+
alignItems: 'center',
95+
mb: 2.5,
96+
}}
97+
>
98+
<Box
99+
sx={{
100+
width: 56,
101+
height: 56,
102+
borderRadius: '50%',
103+
bgcolor: '#ffffff',
104+
display: 'flex',
105+
alignItems: 'center',
106+
justifyContent: 'center',
107+
mb: 1.5,
108+
}}
109+
>
110+
<LanguageIcon sx={{ color: '#1ba4fb', fontSize: 55 }} />
111+
</Box>
112+
<Typography
113+
id="language-selection-title"
114+
sx={{
115+
fontFamily: 'Poppins, Arial, sans-serif',
116+
fontWeight: 500,
117+
fontSize: { xs: '18px', sm: '20px' },
118+
color: '#49454F',
119+
textAlign: 'center',
120+
}}
121+
>
122+
Select your language
123+
</Typography>
124+
</Box>
125+
126+
<Grid
127+
container
128+
spacing={1.5}
129+
id="language-selection-description"
130+
>
131+
{PLP_LANGUAGE_OPTIONS.map((option) => (
132+
<Grid item xs={4} key={option.code}>
133+
<ButtonBase
134+
onClick={() => handleLanguageSelect(option.code)}
135+
sx={{
136+
width: '100%',
137+
border: '1px solid #E0E0E0',
138+
borderRadius: '12px',
139+
py: 1.5,
140+
px: 1,
141+
display: 'flex',
142+
flexDirection: 'column',
143+
alignItems: 'center',
144+
justifyContent: 'center',
145+
minHeight: 72,
146+
transition: 'border-color 0.2s, background-color 0.2s',
147+
'&:hover': {
148+
borderColor: '#BDBDBD',
149+
backgroundColor: '#FAFAFA',
150+
},
151+
}}
152+
>
153+
<Typography
154+
sx={{
155+
fontFamily: 'Poppins, Arial, sans-serif',
156+
fontWeight: option.code === 'en' ? 600 : 500,
157+
fontSize: option.code === 'en' ? '15px' : '16px',
158+
color: '#1F1B13',
159+
lineHeight: 1.3,
160+
textAlign: 'center',
161+
}}
162+
>
163+
{option.nativeLabel}
164+
</Typography>
165+
{option.englishLabel && (
166+
<Typography
167+
sx={{
168+
fontFamily: 'Poppins, Arial, sans-serif',
169+
fontWeight: 400,
170+
fontSize: '12px',
171+
color: '#79747E',
172+
mt: 0.25,
173+
lineHeight: 1.3,
174+
textAlign: 'center',
175+
}}
176+
>
177+
{option.englishLabel}
178+
</Typography>
179+
)}
180+
</ButtonBase>
181+
</Grid>
182+
))}
183+
</Grid>
184+
</Box>
185+
</Dialog>
186+
);
187+
};
188+
189+
export default LanguageSelectionPopup;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export interface LanguageOption {
2+
code: string;
3+
nativeLabel: string;
4+
englishLabel?: string;
5+
}
6+
7+
/** PLP landing language grid — keep in sync with Header language codes */
8+
export const PLP_LANGUAGE_OPTIONS: LanguageOption[] = [
9+
{ code: 'en', nativeLabel: 'English' },
10+
{ code: 'hi', nativeLabel: 'हिंदी', englishLabel: 'Hindi' },
11+
{ code: 'mr', nativeLabel: 'मराठी', englishLabel: 'Marathi' },
12+
{ code: 'odi', nativeLabel: 'ଓଡ଼ିଆ', englishLabel: 'Odia' },
13+
{ code: 'tel', nativeLabel: 'తెలుగు', englishLabel: 'Telugu' },
14+
{ code: 'kan', nativeLabel: 'ಕನ್ನಡ', englishLabel: 'Kannada' },
15+
{ code: 'tam', nativeLabel: 'தமிழ்', englishLabel: 'Tamil' },
16+
{ code: 'guj', nativeLabel: 'ગુજરાતી', englishLabel: 'Gujarati' },
17+
{ code: 'ur', nativeLabel: 'اردو', englishLabel: 'Urdu' },
18+
];
19+
20+
export const PLP_LANGUAGE_POPUP_DISMISSED_KEY = 'plpLanguagePopupDismissed';

libs/shared-lib-v2/src/lib/context/LanguageContext.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ import tam from './locales/tam.json';
3535
// @ts-ignore
3636

3737
import guj from './locales/guj.json';
38+
// @ts-ignore
39+
40+
import ur from './locales/ur.json';
3841

3942
// Define translations object
4043
const translations: Record<string, Record<string, string>> = {
@@ -54,6 +57,8 @@ const translations: Record<string, Record<string, string>> = {
5457
tam,
5558
// @ts-ignore
5659
guj,
60+
// @ts-ignore
61+
ur,
5762
};
5863

5964
// Define RTL languages
@@ -100,6 +105,14 @@ export const LanguageProvider: React.FC<LanguageProviderProps> = ({
100105
}
101106
}, []);
102107

108+
// Apply document direction for RTL languages (e.g. Urdu)
109+
useEffect(() => {
110+
if (typeof document === 'undefined') return;
111+
const dir = rtlLanguages.includes(language) ? 'rtl' : 'ltr';
112+
document.documentElement.setAttribute('dir', dir);
113+
document.documentElement.setAttribute('lang', language);
114+
}, [language]);
115+
103116
// Translate function
104117
const t = useMemo(() => {
105118
return (key: string, options?: { defaultValue?: string }): string => {

0 commit comments

Comments
 (0)