Skip to content

Commit 87a4b4e

Browse files
ZuoTong-xWYK96
andauthored
[feat] Added frontend translations and help tooltips and location dialog. (#21)
1.Add missing translations for the frontend. 2.Add a language parameter to the auth APIs. 3.Add help tooltips. 4.Update the language switch button component. 5.Modify the high-latency pop-up workflow. 6.Add a button that redirects to GitHub. 7.Update the Discord link to a permanent invitation. --------- Co-authored-by: teemo <35056621+WYK96@users.noreply.github.com>
1 parent 742c48c commit 87a4b4e

35 files changed

+760
-205
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,14 @@ next-env.d.ts
5353
# cursor IDE
5454
.cursor
5555

56+
# vscode
57+
.vscode/
58+
5659
# motion_data
5760
motion_data/
5861
*.zip
5962
data/
6063

6164
# weights
6265
weights/
66+

app/components/Scene.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import React, { ReactElement } from 'react'
22
import useBabylonJS from '../hooks/useBabylonJS'
33

4+
/**
5+
* Scene component.
6+
*
7+
* Hosts the BabylonJS canvas and binds the returned ref from useBabylonJS.
8+
*
9+
* @returns ReactElement The canvas element used by BabylonJS.
10+
*/
411
function Scene(): ReactElement {
512
const { canvas: canvas } = useBabylonJS()
613

app/components/auth/Authenticator.tsx

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
'use client'
2+
13
import React, { useState } from 'react'
24
import { useDispatch } from 'react-redux'
35
import { setAuthState } from '@/features/auth/authStore'
@@ -44,7 +46,7 @@ export default function Authenticator({ onAuthSuccess }: AuthenticatorProps) {
4446
const [password, setPassword] = useState('')
4547
const [showPassword, setShowPassword] = useState(false)
4648
const [showError, setShowError] = useState(false)
47-
const [errorMessage, setErrorMessage] = useState('Invalid email or password')
49+
const [errorMessage, setErrorMessage] = useState('')
4850
const [isLoading, setIsLoading] = useState(false)
4951
const dispatch = useDispatch()
5052
const { loadUserCharacters } = usePromptingSettings()
@@ -53,7 +55,7 @@ export default function Authenticator({ onAuthSuccess }: AuthenticatorProps) {
5355
const { showSuccessNotification } = useSuccessNotification()
5456
const { showErrorNotification } = useErrorNotification()
5557
const [codeErrorMessage, setCodeErrorMessage] = useState('')
56-
const { t } = useTranslation()
58+
const { t, i18n } = useTranslation()
5759

5860
const getCurrentPositionAsync = (options: PositionOptions) => {
5961
return new Promise((resolve, reject) => {
@@ -99,7 +101,11 @@ export default function Authenticator({ onAuthSuccess }: AuthenticatorProps) {
99101
const AUTH_STORAGE_KEY = 'dlp3d_auth_state'
100102
if (activeTab === 'register') {
101103
try {
102-
const response = await verifyUser({ username: email, password })
104+
const response = await verifyUser({
105+
username: email,
106+
password,
107+
language: i18n.language,
108+
})
103109
setIsLoading(false)
104110
if (response.auth_code === 200) {
105111
setNeedCode(response.confirmation_required)
@@ -119,7 +125,11 @@ export default function Authenticator({ onAuthSuccess }: AuthenticatorProps) {
119125
}
120126
} else {
121127
try {
122-
const response = await authenticateUser({ username: email, password })
128+
const response = await authenticateUser({
129+
username: email,
130+
password,
131+
language: i18n.language,
132+
})
123133
if (response.auth_code === 200) {
124134
try {
125135
const position = await getCurrentPositionAsync({
@@ -245,13 +255,15 @@ export default function Authenticator({ onAuthSuccess }: AuthenticatorProps) {
245255
setIsLoading(true)
246256
try {
247257
if (!inputCode.trim()) {
248-
setCodeErrorMessage('Please enter the verification code.')
258+
setCodeErrorMessage(t('auth.pleaseEnterTheVerificationCode'))
249259
return
250260
}
251261
// After user confirms email, try authenticating
252262
const response = await fetchResendVerificationCode(email, inputCode)
253263
if (response.auth_code === 200) {
254-
showSuccessNotification(t('notification.verificationCodeSentSuccessfully'))
264+
showSuccessNotification(
265+
t('notification.verificationCodeVerifiedSuccessfully'),
266+
)
255267
setActiveTab('login')
256268
setNeedCode(false)
257269
} else {
@@ -270,9 +282,7 @@ export default function Authenticator({ onAuthSuccess }: AuthenticatorProps) {
270282
// await loginVerify(email, password)
271283
} catch (error) {
272284
console.error(error)
273-
setCodeErrorMessage(
274-
'Invalid or expired verification code, please try again later.',
275-
)
285+
setCodeErrorMessage(t('auth.invalidOrExpiredVerificationCode'))
276286
} finally {
277287
setIsLoading(false)
278288
}

app/components/auth/DeleteUser.tsx

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import React, { useEffect, useState } from 'react'
44
import { Dialog } from '@/components/common/Dialog'
5+
import { useTranslation } from 'react-i18next'
56

67
interface DeleteUserProps {
78
isOpen: boolean
@@ -30,13 +31,13 @@ export default function DeleteUser({
3031
const [password, setPassword] = useState('')
3132
const [showPassword, setShowPassword] = useState(false)
3233
const [localError, setLocalError] = useState('')
33-
34+
const { t } = useTranslation()
3435
const handleSubmit = async (e: React.FormEvent) => {
3536
e.preventDefault()
3637
setLocalError('')
3738

3839
if (!email.trim() || !password.trim()) {
39-
setLocalError('Please fill in all fields.')
40+
setLocalError(t('auth.pleaseFillInAllFields'))
4041
return
4142
}
4243

@@ -54,7 +55,7 @@ export default function DeleteUser({
5455
<Dialog
5556
isOpen={isOpen}
5657
onClose={onClose}
57-
title="Delete Account"
58+
title={t('auth.deleteAccount')}
5859
closeOnBackdropClick={false}
5960
maxWidth="420px"
6061
className="delete-user-dialog"
@@ -69,17 +70,19 @@ export default function DeleteUser({
6970
>
7071
<div style={{ color: '#cfcfe1', lineHeight: 1.6 }}>
7172
<span>
72-
To delete your account, please confirm your email and password.{' '}
73+
{t('auth.toDeleteYourAccountPleaseConfirmYourEmailAndPassword')}
7374
</span>
74-
<span>This action is irreversible.</span>
75+
<span> {t('auth.thisActionIsIrreversible')}</span>
7576
</div>
7677

77-
<label style={{ color: '#8b8ea8', fontSize: '14px' }}>Email</label>
78+
<label style={{ color: '#8b8ea8', fontSize: '14px' }}>
79+
{t('auth.email')}
80+
</label>
7881
<input
7982
type="email"
8083
value={email}
8184
onChange={e => setEmail(e.target.value)}
82-
placeholder="Enter your email"
85+
placeholder={t('auth.enterYourEmail')}
8386
autoComplete="off"
8487
style={{
8588
width: '340px',
@@ -100,13 +103,15 @@ export default function DeleteUser({
100103
}}
101104
/>
102105

103-
<label style={{ color: '#8b8ea8', fontSize: '14px' }}>Password</label>
106+
<label style={{ color: '#8b8ea8', fontSize: '14px' }}>
107+
{t('auth.password')}
108+
</label>
104109
<div style={{ position: 'relative', marginBottom: '0px' }}>
105110
<input
106111
type={showPassword ? 'text' : 'password'}
107112
value={password}
108113
onChange={e => setPassword(e.target.value)}
109-
placeholder="Enter your password"
114+
placeholder={t('auth.enterYourPassword')}
110115
autoComplete="off"
111116
style={{
112117
width: '340px',
@@ -131,12 +136,13 @@ export default function DeleteUser({
131136
onClick={() => setShowPassword(!showPassword)}
132137
style={{
133138
position: 'absolute',
134-
right: '0',
139+
right: '10px',
135140
top: '50%',
136141
transform: 'translateY(-50%)',
137142
background: 'none',
138143
border: 'none',
139144
cursor: 'pointer',
145+
padding: '4px',
140146
borderRadius: '4px',
141147
display: 'flex',
142148
alignItems: 'center',
@@ -205,7 +211,7 @@ export default function DeleteUser({
205211
e.currentTarget.style.color = '#aaa'
206212
}}
207213
>
208-
Cancel
214+
{t('common.cancel')}
209215
</button>
210216
<button
211217
type="submit"
@@ -226,7 +232,7 @@ export default function DeleteUser({
226232
minWidth: '96px',
227233
}}
228234
>
229-
Delete
235+
{t('common.delete')}
230236
</button>
231237
</div>
232238
</form>

app/components/auth/EmailCodeModal.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import React, { useEffect, useState } from 'react'
44
import { Dialog } from '@/components/common/Dialog'
5+
import { useTranslation } from 'react-i18next'
56

67
interface EmailCodeModalProps {
78
isOpen: boolean
@@ -28,7 +29,7 @@ export default function EmailCodeModal({
2829
@returns Promise<void> Resolves when the submit completes.
2930
*/
3031
const [code, setCode] = useState('')
31-
32+
const { t } = useTranslation()
3233
useEffect(() => {
3334
if (isOpen) {
3435
setCode('')
@@ -45,7 +46,7 @@ export default function EmailCodeModal({
4546
<Dialog
4647
isOpen={isOpen}
4748
onClose={onClose}
48-
title="Email verification code"
49+
title={t('auth.emailVerificationCode')}
4950
maxWidth="420px"
5051
className="email-code-dialog"
5152
>
@@ -54,15 +55,15 @@ export default function EmailCodeModal({
5455
style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}
5556
>
5657
<div style={{ color: '#cfcfe1', lineHeight: 1.6 }}>
57-
We have sent a verification code to{' '}
58+
{t('auth.weHaveSentAVerificationCodeTo')}{' '}
5859
<span style={{ color: '#fff', fontWeight: 600 }}>
5960
{email || 'your email'}
6061
</span>{' '}
61-
. Please enter the 6-digit code in the email to complete the verification.
62+
{t('auth.pleaseEnterThe6DigitCodeInTheEmailToCompleteTheVerification')}
6263
</div>
6364

6465
<label style={{ color: '#8b8ea8', fontSize: '14px' }}>
65-
Verification Code
66+
{t('auth.verificationCode')}
6667
</label>
6768
<input
6869
type="text"
@@ -71,7 +72,7 @@ export default function EmailCodeModal({
7172
autoComplete="one-time-code"
7273
value={code}
7374
onChange={e => setCode(e.target.value)}
74-
placeholder="Enter the verification code"
75+
placeholder={t('auth.enterTheVerificationCode')}
7576
style={{
7677
width: '100%',
7778
height: '48px',
@@ -123,7 +124,7 @@ export default function EmailCodeModal({
123124
e.currentTarget.style.color = '#aaa'
124125
}}
125126
>
126-
Cancel
127+
{t('common.cancel')}
127128
</button>
128129

129130
<button
@@ -139,7 +140,7 @@ export default function EmailCodeModal({
139140
minWidth: '96px',
140141
}}
141142
>
142-
Confirm
143+
{t('common.confirm')}
143144
</button>
144145
</div>
145146
</form>

0 commit comments

Comments
 (0)