diff --git a/.gitignore b/.gitignore index 405c92804..3571cf39e 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,6 @@ tests_output/ # IDE .idea + +# create a drafts directory to store draft code/docs for later use +drafts/ diff --git a/.node-version b/.node-version new file mode 100644 index 000000000..dc0bb0f43 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +v22.12.0 diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 000000000..dc0bb0f43 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v22.12.0 diff --git a/src/components/Modals/LinkGeneratorModal.tsx b/src/components/Modals/LinkGeneratorModal.tsx index 47951483b..4ae695c50 100644 --- a/src/components/Modals/LinkGeneratorModal.tsx +++ b/src/components/Modals/LinkGeneratorModal.tsx @@ -3,16 +3,13 @@ import { Modal, Text, Flex, - Divider, - TextInput, Group, Button, CopyButton, Paper, } from '@mantine/core' -import { montserrat_heading, montserrat_paragraph } from 'fonts' import { IconCheck, IconCopy } from '@tabler/icons-react' -import CustomSwitch from '~/components/Switches/CustomSwitch' +import { Switch } from '@/components/shadcn/ui/switch' interface LinkGeneratorModalProps { opened: boolean @@ -78,11 +75,7 @@ export const LinkGeneratorModal = ({ opened={opened} onClose={onClose} title={ - + Generate Shareable Link } @@ -115,11 +108,7 @@ export const LinkGeneratorModal = ({ }} > - + Configure AI behavior settings for your shareable link. These settings will enable specific behaviors when users access the chat through this link. Note: If a setting is enabled course-wide, enabling it here will @@ -128,7 +117,11 @@ export const LinkGeneratorModal = ({ - - handleSettingChange('guidedLearning')(checked) - } + onCheckedChange={handleSettingChange('guidedLearning')} /> - - handleSettingChange('documentsOnly')(checked) - } + onCheckedChange={handleSettingChange('documentsOnly')} /> - - handleSettingChange('systemPromptOnly')(checked) - } + onCheckedChange={handleSettingChange('systemPromptOnly')} /> - + Generated Link @@ -188,7 +179,7 @@ export const LinkGeneratorModal = ({ > : } diff --git a/src/components/Switches/CustomSwitch.tsx b/src/components/Switches/DeprecatedCustomSwitch.tsx similarity index 94% rename from src/components/Switches/CustomSwitch.tsx rename to src/components/Switches/DeprecatedCustomSwitch.tsx index 3eacad730..29cc49526 100644 --- a/src/components/Switches/CustomSwitch.tsx +++ b/src/components/Switches/DeprecatedCustomSwitch.tsx @@ -1,3 +1,8 @@ +/* -------------------------------------------------------------------------- */ +/* WARNING: DEPRECATED!!! */ +/* -------------------------------------------------------------------------- */ +// Use components/shadcn/ui/switch instead + import React, { useState } from 'react' import { Switch, Tooltip, Text } from '@mantine/core' import { IconCheck, IconInfoCircle, IconX } from '@tabler/icons-react' @@ -133,11 +138,6 @@ const CustomSwitch: React.FC = ({ > e.stopPropagation()} > { const queryClient = useQueryClient() - const [introMessage, setIntroMessage] = useState('') + + // Read initial cached data synchronously so child components mount with it + const cachedMetadata = queryClient.getQueryData([ + 'courseMetadata', + project_name, + ]) as CourseMetadata | undefined + + const [introMessage, setIntroMessage] = useState( + cachedMetadata?.course_intro_message || '', + ) const [isIntroMessageUpdated, setIsIntroMessageUpdated] = useState(false) - const [metadata, setMetadata] = useState(null) + const [greetingSaved, setGreetingSaved] = useState( + !!cachedMetadata?.course_intro_message, + ) + const [metadata, setMetadata] = useState( + cachedMetadata ?? null, + ) + const [logoFileName, setLogoFileName] = useState( + cachedMetadata?.banner_image_s3 ? 'Logo uploaded' : null, + ) + const [logoStatus, setLogoStatus] = useState< + 'idle' | 'uploading' | 'success' | 'error' + >(cachedMetadata?.banner_image_s3 ? 'success' : 'idle') + const fileInputRef = useRef(null) - // Update local state when query data changes + // Subscribe to future query cache changes useEffect(() => { const unsubscribe = queryClient.getQueryCache().subscribe(() => { const latestData = queryClient.getQueryData([ @@ -45,29 +68,29 @@ const BrandingForm = ({ }, [project_name, queryClient]) const onUploadLogo = async (logo: File | null) => { - /* - lastModified: 1755022505000 - name: "logo.png" - size: 9399 - type: "image/png" - webkitRelativePath: "" - File Prototype - */ - - // Assuming the file is converted to a URL somewhere else - if (logo) { - console.log('Uploading to s3') - - const banner_s3_image = await uploadToS3( - logo ?? null, - user_id, - project_name, - ) + if (!logo) return + + setLogoFileName(logo.name) + setLogoStatus('uploading') + + const banner_s3_image = await uploadToS3(logo, user_id, project_name) - if (banner_s3_image && metadata) { - metadata.banner_image_s3 = banner_s3_image - await callSetCourseMetadata(project_name, metadata) + if (banner_s3_image && metadata) { + const updatedMetadata = { + ...metadata, + banner_image_s3: banner_s3_image, } + // Only update local state and cache — the S3 key will be + // persisted to the server on the next metadata save + // (greeting update, question save, etc.) + setMetadata(updatedMetadata) + queryClient.setQueryData( + ['courseMetadata', project_name], + updatedMetadata, + ) + setLogoStatus('success') + } else { + setLogoStatus('error') } } @@ -75,83 +98,56 @@ const BrandingForm = ({ <>
-
Greeting
+
Greeting
-
-