(feat:upload) i18n

This commit is contained in:
ManishMadan2882
2025-10-03 20:32:43 +05:30
parent 6bb4195393
commit c184b63df8
10 changed files with 484 additions and 57 deletions

View File

@@ -1,5 +1,6 @@
import React, { useRef } from 'react';
import { useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
import { useDarkTheme } from '../hooks';
import { selectToken } from '../preferences/preferenceSlice';
@@ -24,6 +25,7 @@ const ConnectorAuth: React.FC<ConnectorAuthProps> = ({
onDisconnect,
errorMessage,
}) => {
const { t } = useTranslation();
const token = useSelector(selectToken);
const [isDarkTheme] = useDarkTheme();
const completedRef = useRef(false);
@@ -47,12 +49,16 @@ const ConnectorAuth: React.FC<ConnectorAuthProps> = ({
cleanup();
onSuccess({
session_token: event.data.session_token,
user_email: event.data.user_email || 'Connected User',
user_email:
event.data.user_email ||
t('modals.uploadDoc.connectors.auth.connectedUser'),
});
} else if (errorProvider) {
completedRef.current = true;
cleanup();
onError(event.data.error || 'Authentication failed');
onError(
event.data.error || t('modals.uploadDoc.connectors.auth.authFailed'),
);
}
};
@@ -71,13 +77,15 @@ const ConnectorAuth: React.FC<ConnectorAuthProps> = ({
if (!authResponse.ok) {
throw new Error(
`Failed to get authorization URL: ${authResponse.status}`,
`${t('modals.uploadDoc.connectors.auth.authUrlFailed')}: ${authResponse.status}`,
);
}
const authData = await authResponse.json();
if (!authData.success || !authData.authorization_url) {
throw new Error(authData.error || 'Failed to get authorization URL');
throw new Error(
authData.error || t('modals.uploadDoc.connectors.auth.authUrlFailed'),
);
}
const authWindow = window.open(
@@ -86,9 +94,7 @@ const ConnectorAuth: React.FC<ConnectorAuthProps> = ({
'width=500,height=600,scrollbars=yes,resizable=yes',
);
if (!authWindow) {
throw new Error(
'Failed to open authentication window. Please allow popups.',
);
throw new Error(t('modals.uploadDoc.connectors.auth.popupBlocked'));
}
window.addEventListener('message', handleAuthMessage as any);
@@ -98,13 +104,17 @@ const ConnectorAuth: React.FC<ConnectorAuthProps> = ({
clearInterval(checkClosed);
window.removeEventListener('message', handleAuthMessage as any);
if (!completedRef.current) {
onError('Authentication was cancelled');
onError(t('modals.uploadDoc.connectors.auth.authCancelled'));
}
}
}, 1000);
intervalRef.current = checkClosed;
} catch (error) {
onError(error instanceof Error ? error.message : 'Authentication failed');
onError(
error instanceof Error
? error.message
: t('modals.uploadDoc.connectors.auth.authFailed'),
);
}
};
@@ -147,14 +157,18 @@ const ConnectorAuth: React.FC<ConnectorAuthProps> = ({
d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"
/>
</svg>
<span>Connected as {userEmail}</span>
<span>
{t('modals.uploadDoc.connectors.auth.connectedAs', {
email: userEmail,
})}
</span>
</div>
{onDisconnect && (
<button
onClick={onDisconnect}
className="text-xs font-medium text-[#212121] underline hover:text-gray-700"
>
Disconnect
{t('modals.uploadDoc.connectors.auth.disconnect')}
</button>
)}
</div>

View File

@@ -1,4 +1,5 @@
import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import useDrivePicker from 'react-google-drive-picker';
import ConnectorAuth from './ConnectorAuth';
@@ -26,6 +27,7 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
token,
onSelectionChange,
}) => {
const { t } = useTranslation();
const [selectedFiles, setSelectedFiles] = useState<PickerFile[]>([]);
const [selectedFolders, setSelectedFolders] = useState<PickerFile[]>([]);
const [isLoading, setIsLoading] = useState(false);
@@ -66,14 +68,19 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
if (!validateResponse.ok) {
setIsConnected(false);
setAuthError('Session expired. Please reconnect to Google Drive.');
setAuthError(
t('modals.uploadDoc.connectors.googleDrive.sessionExpired'),
);
setIsValidating(false);
return false;
}
const validateData = await validateResponse.json();
if (validateData.success) {
setUserEmail(validateData.user_email || 'Connected User');
setUserEmail(
validateData.user_email ||
t('modals.uploadDoc.connectors.auth.connectedUser'),
);
setIsConnected(true);
setAuthError('');
setAccessToken(validateData.access_token || null);
@@ -83,14 +90,14 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
setIsConnected(false);
setAuthError(
validateData.error ||
'Session expired. Please reconnect your account.',
t('modals.uploadDoc.connectors.googleDrive.sessionExpiredGeneric'),
);
setIsValidating(false);
return false;
}
} catch (error) {
console.error('Error validating session:', error);
setAuthError('Failed to validate session. Please reconnect.');
setAuthError(t('modals.uploadDoc.connectors.googleDrive.validateFailed'));
setIsConnected(false);
setIsValidating(false);
return false;
@@ -103,15 +110,13 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
const sessionToken = getSessionToken('google_drive');
if (!sessionToken) {
setAuthError('No valid session found. Please reconnect to Google Drive.');
setAuthError(t('modals.uploadDoc.connectors.googleDrive.noSession'));
setIsLoading(false);
return;
}
if (!accessToken) {
setAuthError(
'No access token available. Please reconnect to Google Drive.',
);
setAuthError(t('modals.uploadDoc.connectors.googleDrive.noAccessToken'));
setIsLoading(false);
return;
}
@@ -193,7 +198,7 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
});
} catch (error) {
console.error('Error opening picker:', error);
setAuthError('Failed to open file picker. Please try again.');
setAuthError(t('modals.uploadDoc.connectors.googleDrive.pickerFailed'));
setIsLoading(false);
}
};
@@ -264,9 +269,12 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
<>
<ConnectorAuth
provider="google_drive"
label="Connect to Google Drive"
label={t('modals.uploadDoc.connectors.googleDrive.connect')}
onSuccess={(data) => {
setUserEmail(data.user_email || 'Connected User');
setUserEmail(
data.user_email ||
t('modals.uploadDoc.connectors.auth.connectedUser'),
);
setIsConnected(true);
setAuthError('');
@@ -289,26 +297,34 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
<div className="rounded-lg border border-[#EEE6FF78] dark:border-[#6A6A6A]">
<div className="p-4">
<div className="mb-4 flex items-center justify-between">
<h3 className="text-sm font-medium">Selected Files</h3>
<h3 className="text-sm font-medium">
{t('modals.uploadDoc.connectors.googleDrive.selectedFiles')}
</h3>
<button
onClick={() => handleOpenPicker()}
className="rounded-md bg-[#A076F6] px-3 py-1 text-sm text-white hover:bg-[#8A5FD4]"
disabled={isLoading}
>
{isLoading ? 'Loading...' : 'Select Files'}
{isLoading
? t('modals.uploadDoc.connectors.googleDrive.loading')
: t(
'modals.uploadDoc.connectors.googleDrive.selectFiles',
)}
</button>
</div>
{selectedFiles.length === 0 && selectedFolders.length === 0 ? (
<p className="text-sm text-gray-600 dark:text-gray-400">
No files or folders selected
{t(
'modals.uploadDoc.connectors.googleDrive.noFilesSelected',
)}
</p>
) : (
<div className="max-h-60 overflow-y-auto">
{selectedFolders.length > 0 && (
<div className="mb-2">
<h4 className="mb-1 text-xs font-medium text-gray-500">
Folders
{t('modals.uploadDoc.connectors.googleDrive.folders')}
</h4>
{selectedFolders.map((folder) => (
<div
@@ -317,7 +333,9 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
>
<img
src={folder.iconUrl}
alt="Folder"
alt={t(
'modals.uploadDoc.connectors.googleDrive.folderAlt',
)}
className="mr-2 h-5 w-5"
/>
<span className="flex-1 truncate text-sm">
@@ -337,7 +355,9 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
}}
className="ml-2 text-sm text-red-500 hover:text-red-700"
>
Remove
{t(
'modals.uploadDoc.connectors.googleDrive.remove',
)}
</button>
</div>
))}
@@ -347,7 +367,7 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
{selectedFiles.length > 0 && (
<div>
<h4 className="mb-1 text-xs font-medium text-gray-500">
Files
{t('modals.uploadDoc.connectors.googleDrive.files')}
</h4>
{selectedFiles.map((file) => (
<div
@@ -356,7 +376,9 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
>
<img
src={file.iconUrl}
alt="File"
alt={t(
'modals.uploadDoc.connectors.googleDrive.fileAlt',
)}
className="mr-2 h-5 w-5"
/>
<span className="flex-1 truncate text-sm">
@@ -375,7 +397,9 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
}}
className="ml-2 text-sm text-red-500 hover:text-red-700"
>
Remove
{t(
'modals.uploadDoc.connectors.googleDrive.remove',
)}
</button>
</div>
))}

View File

@@ -43,7 +43,7 @@ export default function UploadToast() {
case 'failed':
return t('attachments.uploadFailed');
default:
return 'Preparing upload';
return t('modals.uploadDoc.progress.preparing');
}
};
@@ -91,8 +91,8 @@ export default function UploadToast() {
onClick={() => toggleTaskCollapse(task.id)}
aria-label={
isCollapsed
? 'Expand upload details'
: 'Collapse upload details'
? t('modals.uploadDoc.progress.expandDetails')
: t('modals.uploadDoc.progress.collapseDetails')
}
className="flex h-8 items-center justify-center p-0 text-black opacity-70 transition-opacity hover:opacity-100 dark:text-white"
>
@@ -108,7 +108,7 @@ export default function UploadToast() {
type="button"
onClick={() => dispatch(dismissUploadTask(task.id))}
className="flex h-8 items-center justify-center p-0 text-black opacity-70 transition-opacity hover:opacity-100 dark:text-white"
aria-label="Dismiss upload toast"
aria-label={t('modals.uploadDoc.progress.dismiss')}
>
<svg
width="16"
@@ -165,7 +165,12 @@ export default function UploadToast() {
aria-valuemin={0}
aria-valuemax={100}
aria-valuenow={formattedProgress}
aria-label={`Upload progress ${formattedProgress}%`}
aria-label={t(
'modals.uploadDoc.progress.uploadProgress',
{
progress: formattedProgress,
},
)}
>
<circle
className="text-gray-300 dark:text-gray-700"
@@ -231,7 +236,7 @@ export default function UploadToast() {
onClick={() => dispatch(clearCompletedTasks())}
className="mt-1 mr-1 text-right text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
>
Clear
{t('modals.uploadDoc.progress.clear')}
</button>
)}
</div>