cleanup: remove test pages
This commit is contained in:
@@ -18,7 +18,6 @@ const adminAtom = atomWithStorage("admin-id", "");
|
|||||||
const pickmeModeAtom = atomWithStorage("pickmeMode", false);
|
const pickmeModeAtom = atomWithStorage("pickmeMode", false);
|
||||||
|
|
||||||
const EditorPage = lazy(() => import("./pages/editor"));
|
const EditorPage = lazy(() => import("./pages/editor"));
|
||||||
const TestPage = lazy(() => import("./pages/test"));
|
|
||||||
const AdminProfilePage = lazy(() => import("./pages/AdminProfile"));
|
const AdminProfilePage = lazy(() => import("./pages/AdminProfile"));
|
||||||
const ClassProfilePage = lazy(() => import("./pages/ClassProfile"));
|
const ClassProfilePage = lazy(() => import("./pages/ClassProfile"));
|
||||||
|
|
||||||
@@ -62,7 +61,6 @@ const pages = {
|
|||||||
"/app": <DX4App {...basePageProps} />,
|
"/app": <DX4App {...basePageProps} />,
|
||||||
"/exit": <ExitPage {...basePageProps} />,
|
"/exit": <ExitPage {...basePageProps} />,
|
||||||
"/editor": <EditorPage {...basePageProps} />,
|
"/editor": <EditorPage {...basePageProps} />,
|
||||||
"/test": <TestPage />,
|
|
||||||
"/adminprofile": <AdminProfilePage {...basePageProps} />,
|
"/adminprofile": <AdminProfilePage {...basePageProps} />,
|
||||||
"/classprofile": <ClassProfilePage {...basePageProps} />,
|
"/classprofile": <ClassProfilePage {...basePageProps} />,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import { AnimatePresence, motion } from "motion/react";
|
import { AnimatePresence, motion } from "motion/react";
|
||||||
import {
|
import {
|
||||||
BiCheck,
|
|
||||||
BiCheckCircle,
|
BiCheckCircle,
|
||||||
BiCopy,
|
BiCopy,
|
||||||
BiLeftArrowAlt,
|
BiLeftArrowAlt,
|
||||||
@@ -10,11 +9,9 @@ import {
|
|||||||
BiPlusCircle,
|
BiPlusCircle,
|
||||||
BiTrash,
|
BiTrash,
|
||||||
BiX,
|
BiX,
|
||||||
BiXCircle,
|
|
||||||
} from "react-icons/bi";
|
} from "react-icons/bi";
|
||||||
import Logo from "../assets/logo.svg";
|
import Logo from "../assets/logo.svg";
|
||||||
import {
|
import {
|
||||||
AdminReq,
|
|
||||||
AdminUpdateRequest,
|
AdminUpdateRequest,
|
||||||
ClassUpdateRequest,
|
ClassUpdateRequest,
|
||||||
getClassProfile,
|
getClassProfile,
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
import { TextPreloader } from "../trash/trash-components";
|
|
||||||
|
|
||||||
export default function TestPage() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="bg-black w-screen h-screen flex items-center justify-center">
|
|
||||||
<TextPreloader />
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,212 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import { DndContext, closestCenter, PointerSensor, TouchSensor, useSensor, useSensors } from '@dnd-kit/core';
|
|
||||||
import { arrayMove, SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
|
||||||
import { CSS } from '@dnd-kit/utilities';
|
|
||||||
|
|
||||||
// Configuration
|
|
||||||
const COLUMNS = [
|
|
||||||
{ key: 'position', label: 'Pos', width: 'w-16', placeholder: '#' },
|
|
||||||
{ key: 'subject', label: 'Subject', width: 'flex-1', placeholder: 'Enter subject' },
|
|
||||||
{ key: 'time', label: 'Time', width: 'w-24', placeholder: '00:00' },
|
|
||||||
{ key: 'room', label: 'Room', width: 'w-20', placeholder: 'A-1' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const INITIAL_DATA = [
|
|
||||||
{ id: '1', position: '1', subject: 'Mathematics', time: '09:00', room: 'A-1' },
|
|
||||||
{ id: '2', position: '2', subject: 'Physics', time: '10:00', room: 'B-2' },
|
|
||||||
{ id: '3', position: '3', subject: 'Chemistry', time: '11:00', room: 'A-3' },
|
|
||||||
{ id: '4', position: '4', subject: 'Biology', time: '13:00', room: 'C-1' },
|
|
||||||
];
|
|
||||||
|
|
||||||
function SortableRow({ item, columns, onUpdate, onDelete }) {
|
|
||||||
const {
|
|
||||||
attributes,
|
|
||||||
listeners,
|
|
||||||
setNodeRef,
|
|
||||||
transform,
|
|
||||||
transition,
|
|
||||||
isDragging,
|
|
||||||
} = useSortable({ id: item.id });
|
|
||||||
|
|
||||||
const style = {
|
|
||||||
transform: CSS.Transform.toString(transform),
|
|
||||||
transition,
|
|
||||||
opacity: isDragging ? 0.5 : 1,
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
ref={setNodeRef}
|
|
||||||
style={style}
|
|
||||||
className="bg-gray-800 rounded-lg overflow-hidden mb-2"
|
|
||||||
>
|
|
||||||
<div className="flex items-stretch">
|
|
||||||
{columns.map((col) => (
|
|
||||||
<input
|
|
||||||
key={col.key}
|
|
||||||
type="text"
|
|
||||||
value={item[col.key] || ''}
|
|
||||||
onChange={(e) => onUpdate(item.id, col.key, e.target.value)}
|
|
||||||
className={`${col.width} px-3 py-3 bg-transparent text-white border-r border-gray-700 last:border-r-0 focus:outline-none focus:bg-gray-700/50 placeholder-gray-500`}
|
|
||||||
placeholder={col.placeholder}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
<div
|
|
||||||
{...attributes}
|
|
||||||
{...listeners}
|
|
||||||
className="w-12 bg-gray-900 flex items-center justify-center cursor-move touch-none select-none text-gray-400 hover:text-white"
|
|
||||||
>
|
|
||||||
⋮
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
onClick={() => onDelete(item.id)}
|
|
||||||
className="w-12 bg-red-600/20 text-red-400 hover:bg-red-600/40 hover:text-red-300 active:bg-red-600/60"
|
|
||||||
>
|
|
||||||
×
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ScheduleEditor({
|
|
||||||
initialData = INITIAL_DATA,
|
|
||||||
columns = COLUMNS,
|
|
||||||
onChange,
|
|
||||||
}) {
|
|
||||||
const [items, setItems] = useState(initialData);
|
|
||||||
|
|
||||||
const sensors = useSensors(
|
|
||||||
useSensor(PointerSensor, {
|
|
||||||
activationConstraint: {
|
|
||||||
distance: 8,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
useSensor(TouchSensor, {
|
|
||||||
activationConstraint: {
|
|
||||||
delay: 200,
|
|
||||||
tolerance: 8,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const updateItems = (newItems) => {
|
|
||||||
setItems(newItems);
|
|
||||||
onChange?.(newItems);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDragEnd = (event) => {
|
|
||||||
const { active, over } = event;
|
|
||||||
|
|
||||||
if (over && active.id !== over.id) {
|
|
||||||
const oldIndex = items.findIndex((item) => item.id === active.id);
|
|
||||||
const newIndex = items.findIndex((item) => item.id === over.id);
|
|
||||||
|
|
||||||
const newItems = arrayMove(items, oldIndex, newIndex);
|
|
||||||
|
|
||||||
// Update positions based on new order
|
|
||||||
const positions = newItems.map(item => item.position);
|
|
||||||
const reorderedItems = newItems.map((item, idx) => ({
|
|
||||||
...item,
|
|
||||||
position: positions[idx]
|
|
||||||
}));
|
|
||||||
|
|
||||||
updateItems(reorderedItems);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUpdate = (id, field, value) => {
|
|
||||||
const newItems = items.map(item =>
|
|
||||||
item.id === id ? { ...item, [field]: value } : item
|
|
||||||
);
|
|
||||||
updateItems(newItems);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDelete = (id) => {
|
|
||||||
const newItems = items.filter(item => item.id !== id);
|
|
||||||
updateItems(newItems);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleAddRow = () => {
|
|
||||||
const newId = String(Date.now());
|
|
||||||
const lastPosition = items.length > 0
|
|
||||||
? String(parseInt(items[items.length - 1].position || '0') + 1)
|
|
||||||
: '1';
|
|
||||||
|
|
||||||
const newItem = { id: newId, position: lastPosition };
|
|
||||||
columns.forEach(col => {
|
|
||||||
if (col.key !== 'position') {
|
|
||||||
newItem[col.key] = '';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
updateItems([...items, newItem]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClear = () => {
|
|
||||||
updateItems([]);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="min-h-screen bg-gray-900 p-4 pb-24">
|
|
||||||
<div className="max-w-3xl mx-auto">
|
|
||||||
<h1 className="text-2xl font-bold mb-6 text-white">
|
|
||||||
Schedule Editor
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<DndContext
|
|
||||||
sensors={sensors}
|
|
||||||
collisionDetection={closestCenter}
|
|
||||||
onDragEnd={handleDragEnd}
|
|
||||||
>
|
|
||||||
<SortableContext
|
|
||||||
items={items.map(item => item.id)}
|
|
||||||
strategy={verticalListSortingStrategy}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
{items.map((item) => (
|
|
||||||
<SortableRow
|
|
||||||
key={item.id}
|
|
||||||
item={item}
|
|
||||||
columns={columns}
|
|
||||||
onUpdate={handleUpdate}
|
|
||||||
onDelete={handleDelete}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</SortableContext>
|
|
||||||
</DndContext>
|
|
||||||
|
|
||||||
{items.length === 0 && (
|
|
||||||
<div className="border-2 border-dashed border-gray-700 rounded-lg p-12 text-center text-gray-500">
|
|
||||||
No items. Add a row to get started.
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="mt-6 flex gap-3">
|
|
||||||
<button
|
|
||||||
onClick={handleAddRow}
|
|
||||||
className="flex-1 bg-blue-600 text-white px-6 py-3 rounded-lg font-semibold hover:bg-blue-700 active:bg-blue-800"
|
|
||||||
>
|
|
||||||
+ Add Row
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={handleClear}
|
|
||||||
className="px-6 py-3 rounded-lg border-2 border-gray-700 text-gray-300 font-semibold hover:bg-gray-800 active:bg-gray-700"
|
|
||||||
>
|
|
||||||
Clear All
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-6 p-4 rounded-lg bg-gray-800 text-sm text-gray-300">
|
|
||||||
<p className="font-bold mb-2 text-white">Instructions:</p>
|
|
||||||
<ul className="space-y-1">
|
|
||||||
<li>• Drag rows by the handle (⋮) on the right to reorder</li>
|
|
||||||
<li>• Positions move with their rows when dragged</li>
|
|
||||||
<li>• Click any field to edit</li>
|
|
||||||
<li>• Click × to delete a row</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user