forked from jappel/leistungsbilanz-ts
Add project transfer controls
This commit is contained in:
parent
da8115fe1d
commit
feec814dc5
5 changed files with 353 additions and 8 deletions
|
|
@ -16,6 +16,11 @@ export interface ProjectSettingsInput {
|
|||
interface ProjectSettingsModalProps {
|
||||
isSaving: boolean;
|
||||
onClose: () => void;
|
||||
onExport: () => Promise<void>;
|
||||
onImport: (
|
||||
transfer: unknown,
|
||||
mode: "replace" | "duplicate"
|
||||
) => Promise<void>;
|
||||
onSave: (input: ProjectSettingsInput) => Promise<void>;
|
||||
project: ProjectDto;
|
||||
}
|
||||
|
|
@ -23,6 +28,8 @@ interface ProjectSettingsModalProps {
|
|||
export function ProjectSettingsModal({
|
||||
isSaving,
|
||||
onClose,
|
||||
onExport,
|
||||
onImport,
|
||||
onSave,
|
||||
project,
|
||||
}: ProjectSettingsModalProps) {
|
||||
|
|
@ -45,6 +52,13 @@ export function ProjectSettingsModal({
|
|||
const [threePhaseVoltageV, setThreePhaseVoltageV] = useState(
|
||||
String(project.threePhaseVoltageV)
|
||||
);
|
||||
const [transfer, setTransfer] = useState<unknown>(null);
|
||||
const [transferFilename, setTransferFilename] = useState("");
|
||||
const [importMode, setImportMode] = useState<"replace" | "duplicate">(
|
||||
"duplicate"
|
||||
);
|
||||
const [replaceConfirmed, setReplaceConfirmed] = useState(false);
|
||||
const [fileError, setFileError] = useState<string | null>(null);
|
||||
|
||||
async function handleSubmit(event: FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault();
|
||||
|
|
@ -64,6 +78,21 @@ export function ProjectSettingsModal({
|
|||
Number(singlePhaseVoltageV) > 0 &&
|
||||
Number(threePhaseVoltageV) > 0;
|
||||
|
||||
async function handleTransferFile(file: File | undefined) {
|
||||
setTransfer(null);
|
||||
setTransferFilename("");
|
||||
setFileError(null);
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
setTransfer(JSON.parse(await file.text()) as unknown);
|
||||
setTransferFilename(file.name);
|
||||
} catch {
|
||||
setFileError("Die ausgewählte Datei enthält kein gültiges JSON.");
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
|
|
@ -193,6 +222,99 @@ export function ProjectSettingsModal({
|
|||
value={threePhaseVoltageV}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-12">
|
||||
<hr className="my-2" />
|
||||
<h3 className="h6">Projekt importieren oder exportieren</h3>
|
||||
<p className="text-secondary small">
|
||||
Der Export enthält den vollständigen unterstützten
|
||||
Projektzustand. Beim Duplizieren bleibt dieses Projekt
|
||||
unverändert.
|
||||
</p>
|
||||
<button
|
||||
className="btn btn-outline-primary mb-3"
|
||||
disabled={isSaving}
|
||||
onClick={() => void onExport()}
|
||||
type="button"
|
||||
>
|
||||
Projektdatei herunterladen
|
||||
</button>
|
||||
<label className="form-label d-block" htmlFor="project-import">
|
||||
Projektdatei auswählen
|
||||
</label>
|
||||
<input
|
||||
accept=".json,application/json"
|
||||
className="form-control"
|
||||
id="project-import"
|
||||
onChange={(event) =>
|
||||
void handleTransferFile(event.target.files?.[0])
|
||||
}
|
||||
type="file"
|
||||
/>
|
||||
{transferFilename ? (
|
||||
<div className="form-text">{transferFilename} ist bereit.</div>
|
||||
) : null}
|
||||
{fileError ? (
|
||||
<div className="text-danger small mt-1">{fileError}</div>
|
||||
) : null}
|
||||
<div className="d-flex flex-wrap gap-3 mt-3">
|
||||
<label className="form-check">
|
||||
<input
|
||||
checked={importMode === "duplicate"}
|
||||
className="form-check-input"
|
||||
name="import-mode"
|
||||
onChange={() => setImportMode("duplicate")}
|
||||
type="radio"
|
||||
/>
|
||||
<span className="form-check-label">
|
||||
Als neues Projekt duplizieren
|
||||
</span>
|
||||
</label>
|
||||
<label className="form-check">
|
||||
<input
|
||||
checked={importMode === "replace"}
|
||||
className="form-check-input"
|
||||
name="import-mode"
|
||||
onChange={() => setImportMode("replace")}
|
||||
type="radio"
|
||||
/>
|
||||
<span className="form-check-label">
|
||||
Dieses Projekt ersetzen
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
{importMode === "replace" ? (
|
||||
<label className="form-check mt-2">
|
||||
<input
|
||||
checked={replaceConfirmed}
|
||||
className="form-check-input"
|
||||
onChange={(event) =>
|
||||
setReplaceConfirmed(event.target.checked)
|
||||
}
|
||||
type="checkbox"
|
||||
/>
|
||||
<span className="form-check-label text-danger">
|
||||
Ich bestätige, dass der aktuelle Projektstand ersetzt
|
||||
wird.
|
||||
</span>
|
||||
</label>
|
||||
) : null}
|
||||
<button
|
||||
className="btn btn-outline-danger mt-3"
|
||||
disabled={
|
||||
isSaving ||
|
||||
transfer === null ||
|
||||
(importMode === "replace" && !replaceConfirmed)
|
||||
}
|
||||
onClick={() =>
|
||||
transfer === null
|
||||
? undefined
|
||||
: void onImport(transfer, importMode)
|
||||
}
|
||||
type="button"
|
||||
>
|
||||
Projektdatei importieren
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue