You need to sign in or sign up before continuing.
Commit 9a38c477 authored by Kantz's avatar Kantz
Browse files

wechsel der Aufgabe nun auch innerhalb des Chats möglich

parent 4cb2901e
...@@ -17,6 +17,11 @@ type TaskPanelProps = { ...@@ -17,6 +17,11 @@ type TaskPanelProps = {
tasksError?: string | null; tasksError?: string | null;
onTaskFileChange?: (fileId: string) => void; onTaskFileChange?: (fileId: string) => void;
onTaskChange?: (taskId: string) => void; onTaskChange?: (taskId: string) => void;
onChangeTaskArea?: () => void;
onPreviousTask?: () => void;
isPreviousTaskDisabled?: boolean;
onNextTask?: () => void;
isNextTaskDisabled?: boolean;
}; };
export default function TaskPanel({ export default function TaskPanel({
...@@ -30,6 +35,11 @@ export default function TaskPanel({ ...@@ -30,6 +35,11 @@ export default function TaskPanel({
tasksError, tasksError,
onTaskFileChange, onTaskFileChange,
onTaskChange, onTaskChange,
onChangeTaskArea,
onPreviousTask,
isPreviousTaskDisabled = false,
onNextTask,
isNextTaskDisabled = false,
}: TaskPanelProps) { }: TaskPanelProps) {
const taskDisplayRef = useRef<HTMLDivElement | null>(null); const taskDisplayRef = useRef<HTMLDivElement | null>(null);
...@@ -49,7 +59,13 @@ export default function TaskPanel({ ...@@ -49,7 +59,13 @@ export default function TaskPanel({
<div className="task-panel-header"> <div className="task-panel-header">
<div className="task-panel-title">{t("task")}</div> <div className="task-panel-title">{t("task")}</div>
{readOnly ? ( {readOnly ? (
<div className="task-panel-lock">{t("taskLocked")}</div> <button
type="button"
className="btn task-panel-change-btn"
onClick={onChangeTaskArea}
>
{t("changeTaskArea")}
</button>
) : ( ) : (
<div className="task-panel-controls"> <div className="task-panel-controls">
<select <select
...@@ -98,6 +114,27 @@ export default function TaskPanel({ ...@@ -98,6 +114,27 @@ export default function TaskPanel({
<div className="task-panel-content" ref={taskDisplayRef}> <div className="task-panel-content" ref={taskDisplayRef}>
{selectedTaskText || t("noTaskSelected")} {selectedTaskText || t("noTaskSelected")}
</div> </div>
{readOnly ? (
<div className="task-panel-nav">
<button
type="button"
className="btn task-panel-nav-btn"
onClick={onPreviousTask}
disabled={!onPreviousTask || isPreviousTaskDisabled}
>
{t("previousTask")}
</button>
<button
type="button"
className="btn task-panel-nav-btn"
onClick={onNextTask}
disabled={!onNextTask || isNextTaskDisabled}
>
{t("nextTask")}
</button>
</div>
) : null}
{tasksError ? <div className="task-panel-error">{tasksError}</div> : null} {tasksError ? <div className="task-panel-error">{tasksError}</div> : null}
</section> </section>
); );
......
...@@ -50,7 +50,9 @@ ...@@ -50,7 +50,9 @@
taskFile: "Task Set", taskFile: "Task Set",
taskId: "Task ID", taskId: "Task ID",
solveWithTutor: "Solve with Tutor", solveWithTutor: "Solve with Tutor",
taskLocked: "Task locked", changeTaskArea: "Change Task Area",
previousTask: "Previous Task",
nextTask: "Next Task",
}, },
de: { de: {
chats: "Chats", chats: "Chats",
...@@ -107,7 +109,9 @@ ...@@ -107,7 +109,9 @@
taskFile: "Aufgabenset", taskFile: "Aufgabenset",
taskId: "Aufgaben-ID", taskId: "Aufgaben-ID",
solveWithTutor: "Mit Tutor lösen", solveWithTutor: "Mit Tutor lösen",
taskLocked: "Aufgabe fixiert", changeTaskArea: "Aufgabengebiet ändern",
previousTask: "Vorherige Aufgabe",
nextTask: "Nächste Aufgabe",
}, },
} as const; } as const;
......
...@@ -9,7 +9,7 @@ import type { ChatMessage } from "../components/Chat/MessageList"; ...@@ -9,7 +9,7 @@ import type { ChatMessage } from "../components/Chat/MessageList";
import type { RetrievedDoc } from "../components/Retrieval/DocPanel"; import type { RetrievedDoc } from "../components/Retrieval/DocPanel";
import { t } from "../i18n"; import { t } from "../i18n";
import { selectTask } from "../api/taskApi"; import { selectTask } from "../api/taskApi";
import { useTutorSession } from "../state/tutorSession"; import { createSessionId, useTutorSession } from "../state/tutorSession";
const initialMessages: ChatMessage[] = []; const initialMessages: ChatMessage[] = [];
...@@ -99,6 +99,7 @@ export default function ChatPage() { ...@@ -99,6 +99,7 @@ export default function ChatPage() {
isTasksInitialized, isTasksInitialized,
selectedTaskRef, selectedTaskRef,
selectedTask, selectedTask,
selectedTaskFile,
taskLocked, taskLocked,
lockTask, lockTask,
unlockTask, unlockTask,
...@@ -181,6 +182,40 @@ export default function ChatPage() { ...@@ -181,6 +182,40 @@ export default function ChatPage() {
return { bySourceKey, bySlug }; return { bySourceKey, bySlug };
}, [directChildren, taskChildren, indirectChildren, subsections, sections]); }, [directChildren, taskChildren, indirectChildren, subsections, sections]);
const nextTaskRef = useMemo(() => {
if (!selectedTaskFile || !selectedTaskRef) {
return null;
}
const currentIndex = selectedTaskFile.tasks.findIndex(
(task) => task.task_id === selectedTaskRef.taskId
);
if (currentIndex < 0) {
return null;
}
const nextTask = selectedTaskFile.tasks[currentIndex + 1];
if (!nextTask) {
return null;
}
return { fileId: selectedTaskFile.file_id, taskId: nextTask.task_id };
}, [selectedTaskFile, selectedTaskRef]);
const previousTaskRef = useMemo(() => {
if (!selectedTaskFile || !selectedTaskRef) {
return null;
}
const currentIndex = selectedTaskFile.tasks.findIndex(
(task) => task.task_id === selectedTaskRef.taskId
);
if (currentIndex <= 0) {
return null;
}
const previousTask = selectedTaskFile.tasks[currentIndex - 1];
if (!previousTask) {
return null;
}
return { fileId: selectedTaskFile.file_id, taskId: previousTask.task_id };
}, [selectedTaskFile, selectedTaskRef]);
const handleSend = async () => { const handleSend = async () => {
const trimmed = draft.trim(); const trimmed = draft.trim();
if (!trimmed) { if (!trimmed) {
...@@ -427,6 +462,67 @@ export default function ChatPage() { ...@@ -427,6 +462,67 @@ export default function ChatPage() {
navigate(isTaskModeEnabled ? "/select-task" : "/chat"); navigate(isTaskModeEnabled ? "/select-task" : "/chat");
}; };
const handleSwitchTask = async (target: { fileId: string; taskId: string } | null) => {
if (!target) {
return;
}
if (messages.length) {
setIsArchiving(true);
try {
await fetch(`/api/chat/archive`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
messages: messages.map((message) => ({
role: message.role,
text: message.text,
})),
draft: chatSessionId,
}),
});
} catch (error) {
void error;
} finally {
setIsArchiving(false);
}
}
const nextSessionId = createSessionId();
resetChatState();
setChatSessionId(nextSessionId);
setTaskRef(target);
lockTask();
try {
await selectTask({
draft: nextSessionId,
fileId: target.fileId,
taskId: target.taskId,
});
} catch (error) {
void error;
return;
}
await loadArchives();
navigate("/chat");
};
const handleNextTask = async () => {
await handleSwitchTask(nextTaskRef);
};
const handlePreviousTask = async () => {
await handleSwitchTask(previousTaskRef);
};
const handleChangeTaskArea = () => {
unlockTask();
navigate("/select-task");
};
const handleOpenSidebar = () => { const handleOpenSidebar = () => {
setIsSidebarOpen(true); setIsSidebarOpen(true);
void loadArchives(); void loadArchives();
...@@ -605,6 +701,11 @@ export default function ChatPage() { ...@@ -605,6 +701,11 @@ export default function ChatPage() {
selectedTaskText={selectedTask.fullText} selectedTaskText={selectedTask.fullText}
selectedFileLabel={selectedTask.title || selectedTask.fileId} selectedFileLabel={selectedTask.title || selectedTask.fileId}
selectedTaskId={selectedTask.taskId} selectedTaskId={selectedTask.taskId}
onChangeTaskArea={handleChangeTaskArea}
onPreviousTask={handlePreviousTask}
isPreviousTaskDisabled={!previousTaskRef || isArchiving}
onNextTask={handleNextTask}
isNextTaskDisabled={!nextTaskRef || isArchiving}
/> />
) : null} ) : null}
......
...@@ -618,16 +618,6 @@ body { ...@@ -618,16 +618,6 @@ body {
align-self: flex-end; align-self: flex-end;
} }
.task-panel-lock {
margin-left: auto;
font-size: 12px;
color: #6f675d;
border: 1px solid #d8d1c4;
border-radius: 999px;
padding: 4px 8px;
background: #fff;
}
.task-panel-meta { .task-panel-meta {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
...@@ -636,6 +626,25 @@ body { ...@@ -636,6 +626,25 @@ body {
color: #6f675d; color: #6f675d;
} }
.task-panel-change-btn {
margin-left: auto;
padding: 4px 10px;
font-size: 11px;
}
.task-panel-nav-btn {
padding: 4px 10px;
font-size: 11px;
}
.task-panel-nav {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 11px;
gap: 10px;
}
@media (max-width: 900px) { @media (max-width: 900px) {
.task-select-controls { .task-select-controls {
grid-template-columns: 1fr; grid-template-columns: 1fr;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment