Add ToggleSwitch component and QuillSense settings management
- Added `ToggleSwitch` component for handling toggles with labels, descriptions, and disabled states. - Introduced `QuillSenseSetting` component for managing QuillSense enablement and advanced prompt settings. - Integrated `QuillSenseSettings` model and API calls for fetching and updating settings.
This commit is contained in:
130
components/book/settings/quillsense/QuillSenseSetting.tsx
Normal file
130
components/book/settings/quillsense/QuillSenseSetting.tsx
Normal file
@@ -0,0 +1,130 @@
|
||||
'use client'
|
||||
import React, {ChangeEvent, forwardRef, useContext, useEffect, useImperativeHandle, useState} from "react";
|
||||
import {BookContext} from "@/context/BookContext";
|
||||
import {SessionContext} from "@/context/SessionContext";
|
||||
import {AlertContext} from "@/context/AlertContext";
|
||||
import {LangContext} from "@/context/LangContext";
|
||||
import System from "@/lib/models/System";
|
||||
import {QuillSenseSettingsProps} from "@/lib/models/QuillSenseSettings";
|
||||
import {useTranslations} from "next-intl";
|
||||
import ToggleSwitch from "@/components/form/ToggleSwitch";
|
||||
import TexteAreaInput from "@/components/form/TexteAreaInput";
|
||||
import InputField from "@/components/form/InputField";
|
||||
import {faMagicWandSparkles, faToggleOn} from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
const QuillSenseSetting = forwardRef(function QuillSenseSetting(props, ref) {
|
||||
const t = useTranslations();
|
||||
const {book, setBook} = useContext(BookContext);
|
||||
const {session} = useContext(SessionContext);
|
||||
const {errorMessage, successMessage} = useContext(AlertContext);
|
||||
const {lang} = useContext(LangContext);
|
||||
|
||||
const [quillsenseEnabled, setQuillsenseEnabled] = useState<boolean>(true);
|
||||
const [advancedPrompt, setAdvancedPrompt] = useState<string>('');
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
handleSave
|
||||
}));
|
||||
|
||||
useEffect((): void => {
|
||||
if (book?.bookId) {
|
||||
fetchQuillSenseSettings();
|
||||
}
|
||||
}, [book?.bookId]);
|
||||
|
||||
async function fetchQuillSenseSettings(): Promise<void> {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const settings: QuillSenseSettingsProps = await System.authGetQueryToServer<QuillSenseSettingsProps>(
|
||||
'book/quillsense-settings',
|
||||
session.accessToken,
|
||||
lang,
|
||||
{bookId: book?.bookId}
|
||||
);
|
||||
setQuillsenseEnabled(settings.quillsenseEnabled);
|
||||
setAdvancedPrompt(settings.advancedPrompt ?? '');
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
errorMessage(e.message);
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSave(): Promise<void> {
|
||||
try {
|
||||
const updateResult: boolean = await System.authPutToServer<boolean>(
|
||||
'book/quillsense-settings',
|
||||
{
|
||||
bookId: book?.bookId,
|
||||
quillsenseEnabled: quillsenseEnabled,
|
||||
advancedPrompt: advancedPrompt
|
||||
},
|
||||
session.accessToken,
|
||||
lang
|
||||
);
|
||||
if (updateResult) {
|
||||
successMessage(t('quillsenseSetting.saveSuccess'));
|
||||
// Mettre a jour le contexte du livre
|
||||
if (setBook && book) {
|
||||
setBook({...book, quillsenseEnabled: quillsenseEnabled});
|
||||
}
|
||||
} else {
|
||||
errorMessage(t('quillsenseSetting.saveError'));
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
errorMessage(e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex items-center justify-center p-8">
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6 p-4">
|
||||
<div className="bg-secondary/20 rounded-xl p-5 shadow-inner border border-secondary/30">
|
||||
<InputField
|
||||
icon={faToggleOn}
|
||||
fieldName={t('quillsenseSetting.enableQuillsense')}
|
||||
input={
|
||||
<ToggleSwitch
|
||||
checked={quillsenseEnabled}
|
||||
onChange={(checked: boolean): void => setQuillsenseEnabled(checked)}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<p className="text-muted text-sm mt-2">
|
||||
{t('quillsenseSetting.enableDescription')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-secondary/20 rounded-xl p-5 shadow-inner border border-secondary/30">
|
||||
<InputField
|
||||
icon={faMagicWandSparkles}
|
||||
fieldName={t('quillsenseSetting.advancedPrompt')}
|
||||
input={
|
||||
<TexteAreaInput
|
||||
value={advancedPrompt}
|
||||
setValue={(e: ChangeEvent<HTMLTextAreaElement>): void => setAdvancedPrompt(e.target.value)}
|
||||
placeholder={t('quillsenseSetting.advancedPromptPlaceholder')}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<p className="text-muted text-sm mt-2">
|
||||
{t('quillsenseSetting.advancedPromptDescription')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default QuillSenseSetting;
|
||||
59
components/form/ToggleSwitch.tsx
Normal file
59
components/form/ToggleSwitch.tsx
Normal file
@@ -0,0 +1,59 @@
|
||||
'use client';
|
||||
|
||||
import {Dispatch, SetStateAction} from 'react';
|
||||
|
||||
interface ToggleSwitchProps {
|
||||
enabled: boolean;
|
||||
setEnabled: Dispatch<SetStateAction<boolean>>;
|
||||
label?: string;
|
||||
description?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export default function ToggleSwitch({
|
||||
enabled,
|
||||
setEnabled,
|
||||
label,
|
||||
description,
|
||||
disabled = false
|
||||
}: ToggleSwitchProps) {
|
||||
function handleToggle(): void {
|
||||
if (!disabled) {
|
||||
setEnabled(!enabled);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
{label && (
|
||||
<span className="text-text-primary font-medium">{label}</span>
|
||||
)}
|
||||
{description && (
|
||||
<span className="text-text-secondary text-sm mt-1">{description}</span>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleToggle}
|
||||
disabled={disabled}
|
||||
className={`
|
||||
relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent
|
||||
transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2
|
||||
${enabled ? 'bg-primary' : 'bg-secondary'}
|
||||
${disabled ? 'opacity-50 cursor-not-allowed' : ''}
|
||||
`}
|
||||
role="switch"
|
||||
aria-checked={enabled}
|
||||
>
|
||||
<span
|
||||
className={`
|
||||
pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0
|
||||
transition duration-200 ease-in-out
|
||||
${enabled ? 'translate-x-5' : 'translate-x-0'}
|
||||
`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
4
lib/models/QuillSenseSettings.ts
Normal file
4
lib/models/QuillSenseSettings.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface QuillSenseSettingsProps {
|
||||
quillsenseEnabled: boolean;
|
||||
advancedPrompt: string | null;
|
||||
}
|
||||
Reference in New Issue
Block a user