feat: Added viewer
This commit is contained in:
156
viewer/app/view.tsx
Normal file
156
viewer/app/view.tsx
Normal file
@@ -0,0 +1,156 @@
|
||||
"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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user