Files
ontime/apps/client/src/features/app-settings/panel/project-panel/ManageProjects.tsx
T
Carlos Valente 1849b4d39f Deps migration (#1988)
* chore: migrate eslint to oxlint

* chore: migrate prettier to oxfmt

* chore: migrate typescript

* chore: toThrow should have a expected value

* chore: cast test value as Day

* chore: small title fix

* chore: mocks should be hoisted

* chore: incorrect async useage

* chore: test should be inside description

* chore: test sohuld include an expeced

* chore: oxfmt

---------

Co-authored-by: alex-Arc <omnivox@LAPTOP-RC5SNBVV.localdomain>
2026-03-08 16:22:12 +01:00

91 lines
2.7 KiB
TypeScript

import { ChangeEvent, useRef, useState } from 'react';
import { IoAdd } from 'react-icons/io5';
import { useSearchParams } from 'react-router';
import { uploadProjectFile } from '../../../../common/api/db';
import { invalidateAllCaches, maybeAxiosError } from '../../../../common/api/utils';
import Button from '../../../../common/components/buttons/Button';
import { validateProjectFile } from '../../../../common/utils/uploadUtils';
import * as Panel from '../../panel-utils/PanelUtils';
import ProjectCreateForm from './ProjectCreateForm';
import ProjectList from './ProjectList';
export default function ManageProjects() {
const [searchParams, setSearchParams] = useSearchParams();
const [error, setError] = useState('');
const [loading, setLoading] = useState<'import' | null>(null);
const fileInputRef = useRef<HTMLInputElement>(null);
const isCreatingProject = searchParams.get('new') === 'true';
const handleToggleCreate = () => {
searchParams.set('new', isCreatingProject ? 'false' : 'true');
setSearchParams(searchParams);
};
const handleSelectFile = () => {
fileInputRef.current?.click();
};
const handleImport = async (event: ChangeEvent<HTMLInputElement>) => {
const selectedFile = event.target?.files?.[0];
if (!selectedFile) {
return;
}
setLoading('import');
try {
validateProjectFile(selectedFile);
await uploadProjectFile(selectedFile);
} catch (error) {
const errorMessage = maybeAxiosError(error);
setError(`Error uploading file: ${errorMessage}`);
} finally {
await invalidateAllCaches();
}
setLoading(null);
};
const handleCloseForm = () => {
searchParams.delete('new');
setSearchParams(searchParams);
};
return (
<Panel.Section>
<input
ref={fileInputRef}
style={{ display: 'none' }}
type='file'
onChange={handleImport}
accept='.json'
data-testid='file-input'
/>
<Panel.Card>
<Panel.SubHeader>
Manage projects
<Panel.InlineElements>
<Button
onClick={handleSelectFile}
disabled={Boolean(loading) || isCreatingProject}
loading={loading === 'import'}
>
Import
</Button>
<Button onClick={handleToggleCreate} disabled={Boolean(loading) || isCreatingProject}>
New <IoAdd />
</Button>
</Panel.InlineElements>
</Panel.SubHeader>
{error && <Panel.Error>{error}</Panel.Error>}
<Panel.Divider />
{isCreatingProject && <ProjectCreateForm onClose={handleCloseForm} />}
<ProjectList />
</Panel.Card>
</Panel.Section>
);
}