Skip to content

Commit cc2cf93

Browse files
committed
fix: preference page design
1 parent 5854aa9 commit cc2cf93

File tree

5 files changed

+80
-53
lines changed

5 files changed

+80
-53
lines changed

apps/pro-web/components/routes/preferences/google-translation.tsx

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ const GoogleTranslate: React.FC<GoogleTranslateProps> = ({
1818
includedLanguages = 'en,es,fr,de,it,pt,ru,ja,ko,zh-CN,zh-TW,ar',
1919
}) => {
2020
const initialized = useRef(false)
21-
const prefsInitialized = useRef(false)
2221
const containerRef = useRef<HTMLDivElement>(null)
2322
const [currentLanguage, setCurrentLanguage] = useState('en')
2423
const { data: session } = useSession()
@@ -27,39 +26,52 @@ const GoogleTranslate: React.FC<GoogleTranslateProps> = ({
2726

2827
useEffect(() => {
2928
if (!preferences) return
30-
if (prefsInitialized.current) return
3129

3230
const defaultLang = preferences.lang || 'en'
3331
setCurrentLanguage(defaultLang)
34-
35-
prefsInitialized.current = true
32+
console.log('Setting initial language from preferences:', defaultLang)
3633
}, [preferences])
3734

35+
const reloadGoogleTranslate = () => {
36+
// Remove existing script
37+
const oldScript = document.querySelector(
38+
'script[src*="translate.google.com"]',
39+
)
40+
if (oldScript) oldScript.remove()
41+
42+
// Remove existing widget container
43+
if (containerRef.current) containerRef.current.innerHTML = ''
44+
45+
// Re-add script
46+
const script = document.createElement('script')
47+
script.src =
48+
'//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit'
49+
script.async = true
50+
document.head.appendChild(script)
51+
}
52+
3853
const handleLanguageChange = async (langCode: string) => {
3954
try {
4055
setCurrentLanguage(langCode)
4156

42-
// 1️⃣ Try to use Google Translate instance if available
43-
const translateInstance =
44-
window.google?.translate?._getInstanceIfExists?.()
45-
if (translateInstance) {
46-
translateInstance.translatePage(pageLanguage, langCode)
47-
console.log('Translation triggered via Google API')
48-
return
49-
}
50-
57+
// Save user preference
5158
if (user?.id && user?.hasuraJwt) {
52-
document.cookie = `googtrans=/en/${langCode}; domain=${window.location.hostname}; path=/`
53-
54-
// Save preference in DB
5559
setPreferences({ lang: langCode })
56-
setTimeout(() => {
57-
// Reload page to apply translation
58-
window.location.reload()
59-
}, 500)
6060
}
61-
} catch (error) {
62-
console.error('Failed to change language:', error)
61+
62+
// Set cookie BEFORE initializing Google script
63+
document.cookie = `googtrans=/en/${langCode}; path=/`
64+
document.cookie = `googtrans=/en/${langCode}; domain=${window.location.hostname}; path=/`
65+
66+
// Re-init Google translate so it picks up cookie
67+
reloadGoogleTranslate()
68+
69+
// Reload page AFTER script has executed
70+
setTimeout(() => {
71+
window.location.reload()
72+
}, 600)
73+
} catch (err) {
74+
console.error('Language switch failed', err)
6375
}
6476
}
6577

apps/pro-web/components/routes/preferences/preference-section.tsx

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@ export function PreferenceSection({ title, items }: PreferenceSectionProps) {
5959
const { data: session, update } = useSession()
6060
const { customSonner } = useSonner()
6161
const { currentUser, getUserInfo, updateUserDetails } = useProfile()
62-
const [errorMessage, setErrorMessage] = useState('')
62+
const [errorMessage, setErrorMessage] = useState({
63+
inputId: '',
64+
message: '',
65+
})
6366
const [isLoading, setIsLoading] = useState(false)
6467
const [sendindVEmail, setSendingVEmail] = useState(false)
6568
const [inputValue, setInputValue] = useState({ username: '', email: '' })
@@ -69,13 +72,13 @@ export function PreferenceSection({ title, items }: PreferenceSectionProps) {
6972
const user = session?.user
7073

7174
useEffect(() => {
72-
if (currentUser) {
75+
if (session) {
7376
setInputValue({
74-
username: currentUser.username || '',
75-
email: currentUser.email || '',
77+
username: session.user?.name || '',
78+
email: session.user?.email || '',
7679
})
7780
}
78-
}, [currentUser])
81+
}, [session])
7982

8083
function executeButton(buttonText: string) {
8184
setDeleteDialogOpen(true)
@@ -178,8 +181,8 @@ export function PreferenceSection({ title, items }: PreferenceSectionProps) {
178181
if (!user) throw new Error('No user session found. Aborting...')
179182

180183
const preferencesUpdate = await updatePreferences({
181-
jwt: user.hasuraJwt,
182-
userId: user.id,
184+
jwt: user?.hasuraJwt,
185+
userId: user?.id,
183186
preferencesSet,
184187
})
185188

@@ -242,17 +245,20 @@ export function PreferenceSection({ title, items }: PreferenceSectionProps) {
242245
setInputValue((prev) => ({ ...prev, [inputId]: value }))
243246

244247
if (inputId === 'username') {
245-
const usernameRegex = /^[a-zA-Z0-9_]{3,24}$/
248+
const usernameRegex = /^[a-zA-Z0-9_]+( [a-zA-Z0-9_]+)*$/
246249

247-
if (!usernameRegex.test(value)) {
248-
setErrorMessage(
249-
'Username must be 3–24 characters and contain only letters, numbers, or underscores.',
250-
)
251-
console.error('Invalid username format:', value)
250+
if (value.length < 3 || value.length > 24 || !usernameRegex.test(value)) {
251+
setErrorMessage({
252+
inputId,
253+
message:
254+
'Username must be 3-24 characters long and can only contain letters, numbers, and underscores.',
255+
})
252256
return
253257
}
258+
console.error('Invalid username format:', value)
259+
return
254260
}
255-
setErrorMessage('')
261+
setErrorMessage({ inputId: '', message: '' })
256262
}
257263

258264
async function handleUpdateProfile() {
@@ -264,10 +270,10 @@ export function PreferenceSection({ title, items }: PreferenceSectionProps) {
264270
return
265271
}
266272

267-
if (session.user.slug !== currentUser?.slug) {
273+
if (!user.slug) {
268274
customSonner({
269275
type: 'error',
270-
text: `You must be logged in as ${currentUser?.slug} to update your profile.`,
276+
text: `You must be logged in as ${user?.slug} to update your profile.`,
271277
})
272278
return
273279
}
@@ -277,7 +283,7 @@ export function PreferenceSection({ title, items }: PreferenceSectionProps) {
277283
try {
278284
const { username } = inputValue
279285
const slug = toSlug(username)
280-
const email = currentUser?.email
286+
const email = user?.email
281287

282288
await updateUserDetails(email ?? null, username ?? null, slug ?? null)
283289

@@ -375,6 +381,7 @@ export function PreferenceSection({ title, items }: PreferenceSectionProps) {
375381

376382
if (type === 'font-size') {
377383
const fontVal = value as FontSizeType
384+
const userId = user?.id as string
378385
setPreferences({ lang: preferences.lang, fontSize: fontVal })
379386
return
380387
}
@@ -384,6 +391,11 @@ export function PreferenceSection({ title, items }: PreferenceSectionProps) {
384391
if (type === 'theme') return theme
385392
if (type === 'font-size') return preferences.fontSize
386393
}
394+
395+
console.log({
396+
preferences,
397+
})
398+
387399
return (
388400
<>
389401
<AlertDialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
@@ -415,23 +427,23 @@ export function PreferenceSection({ title, items }: PreferenceSectionProps) {
415427

416428
<Accordion key={title} type="single" collapsible defaultValue="1">
417429
<AccordionItem value="1" className="border-none">
418-
<AccordionTrigger className="hover:no-underline dark:bg-mirage bg-gray-300 px-4 py-5 mt-3">
430+
<AccordionTrigger className="hover:no-underline dark:bg-black bg-gray-200 px-4 py-5 mt-3">
419431
<p className="text-2xl">{title}</p>
420432
</AccordionTrigger>
421433
<AccordionContent>
422-
<Card className="bg-transparent dark:border-mirage border-gray-300 border-t-0 -mt-7">
434+
<Card className="dark:bg-black bg-gray-200 -mt-7">
423435
<CardContent className="flex flex-col items-center justify-center w-full px-4 pt-[3rem] gap-y-4">
424436
{items.map((item, idx) => (
425437
<div
426438
key={item.title}
427439
className={cn(
428-
'flex justify-between dark:bg-mirage bg-gray-300 items-center gap-x-5 px-5 py-4 border-b dark:border-mirage border-gray-300 pb-5 w-full',
440+
'flex justify-between dark:bg-muted/50 bg-white items-center gap-x-5 px-5 py-4 border-b dark:border-mirage border-gray-300 pb-5 w-full',
429441
idx === items.length - 1 ? 'border-none' : '',
430442
)}
431443
>
432444
{item.type === 'input' ? (
433445
<div className="space-y-2 w-full ">
434-
<Label htmlFor="password">
446+
<Label htmlFor={item.props?.inputId}>
435447
{item.props?.inputName}
436448
</Label>
437449
<div className="relative w-full flex space-x-4">
@@ -457,7 +469,9 @@ export function PreferenceSection({ title, items }: PreferenceSectionProps) {
457469
{item.props?.asInlineButton && (
458470
<Button
459471
onClick={() => handleUpdateProfile()}
460-
disabled={isLoading || !currentUser}
472+
disabled={
473+
isLoading || !user || !!errorMessage.message
474+
}
461475
id={item.props?.buttonId}
462476
className="p-2 text-sm min-h-9"
463477
>
@@ -474,7 +488,11 @@ export function PreferenceSection({ title, items }: PreferenceSectionProps) {
474488
)}
475489
</div>
476490
<div>
477-
<span className="text-red-700">{errorMessage}</span>
491+
<span className="text-red-700">
492+
{errorMessage.inputId === item.props?.inputId
493+
? errorMessage.message
494+
: ''}
495+
</span>
478496
</div>
479497
</div>
480498
) : null}

apps/pro-web/lib/constants/preferences.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,6 @@ export const languageOptions = [
217217
{ value: 'ru', label: 'Русский', flag: '🇷🇺' },
218218
{ value: 'ja', label: '日本語', flag: '🇯🇵' },
219219
{ value: 'ko', label: '한국어', flag: '🇰🇷' },
220-
{ value: 'zh-CN', label: '简体中文', flag: '🇨🇳' }, // Simplified Chinese
221-
{ value: 'ar', label: 'العربية', flag: '🇸🇦' }, // Arabic
220+
//{ value: 'zh-CN', label: '简体中文', flag: '🇨🇳' }, // Simplified Chinese
221+
//{ value: 'ar', label: 'العربية', flag: '🇸🇦' }, // Arabic
222222
]

apps/web/components/routes/preferences/preference-section.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -427,17 +427,17 @@ export function PreferenceSection({ title, items }: PreferenceSectionProps) {
427427

428428
<Accordion key={title} type="single" collapsible defaultValue="1">
429429
<AccordionItem value="1" className="border-none">
430-
<AccordionTrigger className="hover:no-underline dark:bg-mirage bg-gray-300 px-4 py-5 mt-3">
430+
<AccordionTrigger className="hover:no-underline dark:bg-black bg-gray-200 px-4 py-5 mt-3">
431431
<p className="text-2xl">{title}</p>
432432
</AccordionTrigger>
433433
<AccordionContent>
434-
<Card className="bg-transparent dark:border-mirage border-gray-300 border-t-0 -mt-7">
434+
<Card className="dark:bg-black bg-gray-200 -mt-7">
435435
<CardContent className="flex flex-col items-center justify-center w-full px-4 pt-[3rem] gap-y-4">
436436
{items.map((item, idx) => (
437437
<div
438438
key={item.title}
439439
className={cn(
440-
'flex justify-between dark:bg-mirage bg-gray-300 items-center gap-x-5 px-5 py-4 border-b dark:border-mirage border-gray-300 pb-5 w-full',
440+
'flex justify-between dark:bg-muted/50 bg-white items-center gap-x-5 px-5 py-4 border-b dark:border-mirage border-gray-300 pb-5 w-full',
441441
idx === items.length - 1 ? 'border-none' : '',
442442
)}
443443
>

apps/web/lib/hooks/use-preferences.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,6 @@ export function PreferencesProvider({
5656
const dbPrefs = await getUserPreferences(userId, jwt)
5757
const data = dbPrefs.data
5858
if (data) {
59-
console.log({
60-
'fetching preferences data:': data,
61-
})
6259
setPreferencesState({
6360
lang: (data.lang as string) || DEFAULT_PREFERENCES.lang,
6461
fontSize: (data.fontSize as FontSize) || localFontSize,

0 commit comments

Comments
 (0)