157 lines
4.5 KiB
TypeScript
157 lines
4.5 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { useForm } from "react-hook-form";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Form,
|
|
FormControl,
|
|
FormDescription,
|
|
FormField,
|
|
FormItem,
|
|
FormLabel,
|
|
FormMessage,
|
|
} from "@/components/ui/form";
|
|
import { Input } from "@/components/ui/input";
|
|
import { SubstitutionData, LocalData } from "@/lib/types";
|
|
import { Card, CardContent } from "@/components/ui/card";
|
|
import ScheduleViewer from "@/components/own/schedule-viewer";
|
|
|
|
interface ViewProps {
|
|
data: SubstitutionData | null;
|
|
}
|
|
|
|
interface FormValues {
|
|
className: string;
|
|
jsonFile: FileList | null;
|
|
}
|
|
|
|
export default function View({ data }: ViewProps) {
|
|
const [loading, setLoading] = useState(true);
|
|
const [localData, setLocalData] = useState<LocalData | null>(null);
|
|
|
|
const form = useForm<FormValues>({
|
|
defaultValues: {
|
|
className: "",
|
|
jsonFile: null,
|
|
},
|
|
});
|
|
|
|
const onSubmit = async (values: FormValues) => {
|
|
const classNameProcessed = values.className.toLowerCase();
|
|
|
|
const file = values.jsonFile?.[0];
|
|
if (!file) {
|
|
alert("No file uploaded!");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const text = await file.text();
|
|
const jsonData = JSON.parse(text);
|
|
console.log(jsonData)
|
|
|
|
const foundKey = Object.keys(jsonData).find(k => k.toLowerCase() === classNameProcessed);
|
|
|
|
if (!foundKey) {
|
|
alert("Class not found in file!");
|
|
return;
|
|
}
|
|
|
|
const data = {
|
|
class: classNameProcessed,
|
|
timetable: jsonData[foundKey]
|
|
};
|
|
|
|
setLocalData(data);
|
|
localStorage.setItem("data", JSON.stringify(data));
|
|
|
|
} catch (err) {
|
|
console.log(err)
|
|
alert("Invalid JSON file.");
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
const saved = localStorage.getItem("data");
|
|
if (saved) {
|
|
setLocalData(JSON.parse(saved));
|
|
}
|
|
setLoading(false);
|
|
}, [data]);
|
|
|
|
if (loading) return <p>Loading...</p>;
|
|
|
|
if (!localData) {
|
|
return (
|
|
<div className="flex justify-center w-full">
|
|
<Card className="my-8 max-w-200">
|
|
<CardContent>
|
|
<Form {...form} >
|
|
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
|
<FormField
|
|
control={form.control}
|
|
name="className"
|
|
rules={{
|
|
required: "Třída je povinná",
|
|
pattern: {
|
|
value: /^[AEC][1-4][a-c]?$/i,
|
|
message: "Neplatný název třídy"
|
|
},
|
|
}}
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Třída</FormLabel>
|
|
<FormControl>
|
|
<Input {...field} placeholder="C2c" />
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
|
|
<FormField
|
|
control={form.control}
|
|
name="jsonFile"
|
|
rules={{ required: "Soubor je povinný" }}
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Soubor</FormLabel>
|
|
<FormControl>
|
|
<input
|
|
type="file"
|
|
accept=".json"
|
|
onChange={(e) => field.onChange(e.target.files)}
|
|
className="cursor-pointer"
|
|
/>
|
|
</FormControl>
|
|
<FormDescription>
|
|
<a href="/posts/viewer/getting_file" target="_blank" className="hover:underline">
|
|
Jak získat soubor?
|
|
</a>
|
|
</FormDescription>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
|
|
<Button type="submit" className="cursor-pointer">Odeslat</Button>
|
|
</form>
|
|
</Form>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="w-full max-w-[1920px] mx-auto p-4 space-y-6">
|
|
<div className="flex justify-between items-center">
|
|
<h1 className="text-2xl font-bold">Rozvrh třídy {localData.class}</h1>
|
|
<Button variant="outline" onClick={() => setLocalData(null)}>Změnit třídu/soubor</Button>
|
|
</div>
|
|
<ScheduleViewer localData={localData} substitutionData={data} />
|
|
</div>
|
|
);
|
|
}
|