CUSW-chula / cusw-frontend

MIT License
0 stars 0 forks source link

(bug) -> editor.replaceBlocks is loop #29

Closed bypkt-bk closed 12 hours ago

bypkt-bk commented 15 hours ago
'use client';
import 'yjs';
import { ChangeEvent, useCallback, useEffect, useState } from 'react';
import { Displayfile, Uploadfile } from './uploadfile';
import Emoji from './emoji';
import { BlockNoteView } from '@blocknote/shadcn';
import '@blocknote/shadcn/style.css';
import { useCreateBlockNote } from '@blocknote/react';
import { type Block, BlockNoteSchema, defaultBlockSpecs } from '@blocknote/core';
import * as Button from '@/components/ui/button';
import * as Card from '@/components/ui/card';
import * as DropdownMenu from '@/components/ui/dropdown-menu';
import * as Form from '@/components/ui/form';
import * as Input from '@/components/ui/input';
import * as Label from '@/components/ui/label';
import * as Popover from '@/components/ui/popover';
import * as Tabs from '@/components/ui/tabs';
import * as Toggle from '@/components/ui/toggle';
import * as Tooltip from '@/components/ui/tooltip';
interface Files {
  id: string;
  fileName: string;
  filePath: string;
  fileSize: number;
  taskId: string;
  projectId: string;
  uploadedBy: string;
  createdAt: Date;
}

interface Textedit {
  title: string;
  description: string;
}
const Workspace = () => {
  const [TexteditList, setTexteditList] = useState<Textedit | null>(null);

  const pareJsonValues = useCallback((values: any) => {
    const newValue: Textedit = {
      title: values.title,
      description: values.description,
    };
    return newValue;
  }, []);

  const fetchTextedit = useCallback(async () => {
    try {
      const response = await fetch(
        'http://localhost:4000/api/tasks/textedit/cm24lq0sx0001jkpdbc9lxu8x',
      );
      const data = await response.json();
      setTexteditList(data);
      console.log('Initial Textedit list:', data);
    } catch (error) {
      console.error('Error fetching Textedit:', error);
    }
  }, []);

  useEffect(() => {
    fetchTextedit();
  }, []);

  const [fileList, setFileList] = useState<Files[]>([]);

  // biome-ignore lint/suspicious/noExplicitAny: <explanation>
  const pareJsonValue = useCallback((values: any) => {
    const newValue: Files = {
      id: values.id,
      createdAt: values.createdAt,
      fileName: values.fileName,
      filePath: values.filePath,
      fileSize: values.fileSize,
      projectId: values.projectId,
      taskId: values.taskId,
      uploadedBy: values.uploadBy,
    };
    return newValue;
  }, []);

  useEffect(() => {
    const fetchFile = async () => {
      try {
        const response = await fetch('http://localhost:4000/api/file/cm24lq0sx0001jkpdbc9lxu8x');
        const data = await response.json();
        setFileList(data);
        console.log('Initial file list:', data);
      } catch (error) {
        console.error('Error fetching files:', error);
      }
    };

    fetchFile();

    const ws = new WebSocket('ws://localhost:3001');
    ws.onopen = () => {
      console.log('Connected to WebSocket');
    };

    ws.onmessage = (event) => {
      try {
        const socketEvent = JSON.parse(event.data);
        const { eventName, data } = socketEvent;
        const parsedData = pareJsonValue(data);

        if (eventName === 'add-file') {
          setFileList((prevFiles) => [...prevFiles, parsedData]);
        } else if (eventName === 'remove-file') {
          setFileList((prevFiles) => prevFiles.filter((file) => file.id !== parsedData.id));
        }
      } catch (error) {
        console.error('Error parsing WebSocket message:', error);
      }
    };

    ws.onclose = () => {
      console.log('WebSocket connection closed');
    };

    return () => {
      ws.close();
    };
  }, [pareJsonValue]);

  // disable blocks you don't want
  const { audio, image, video, file, codeBlock, ...allowedBlockSpecs } = defaultBlockSpecs;

  const schema = BlockNoteSchema.create({
    blockSpecs: {
      ...allowedBlockSpecs,
    },
  });

  const handleTextingActions = useCallback(async () => {
    if (!TexteditList) return;
    const taskId = 'cm24lq0sx0001jkpdbc9lxu8x';
    const userId = 'cm24ll4370008kh59coznldal';
    const url = 'http://localhost:4000/api/tasks/textedit';
    const options = {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        taskId,
        userId,
        title: TexteditList.title,
        description: TexteditList.description,
      }),
    };

    try {
      const response = await fetch(url, options);
      if (!response.ok) throw new Error(`Error: ${response.statusText}`);
      const data = await response.json();
      console.log('Textedit updated successfully:', data);
    } catch (error) {
      console.error('Error updating textedit:', error);
    }
  }, [TexteditList]);

  useEffect(() => {
    if (TexteditList) {
      handleTextingActions();
    }
  }, [TexteditList, handleTextingActions]);

  const editor = useCreateBlockNote({
    schema,
  });

  const onChangeBlock = async () => {
    const html = await editor.blocksToHTMLLossy(editor.document);
    setTexteditList((prev) => (prev ? { ...prev, description: JSON.stringify(html) } : null));
  };

  console.log('TexteditList?.description : ', TexteditList?.description);

  async function loadInitialHTML() {
    const blocks = await editor.tryParseHTMLToBlocks(TexteditList?.description || '');
    editor.replaceBlocks(editor.document, blocks);
  }
  loadInitialHTML();

  return (
    <div>
      <input
        className="resize-none border-none w-full outline-none pl-[54px] placeholder-gray-300 text-[30px] leading-[36px] font-semibold font-Anuphan"
        placeholder="Task Title"
        value={TexteditList?.title || ''}
        onChange={(e) =>
          setTexteditList((prev) => (prev ? { ...prev, title: e.target.value } : null))
        } // Update edited content on change
      />
      <BlockNoteView
        editor={editor}
        emojiPicker={false}
        theme={'light'}
        onChange={onChangeBlock}
        shadCNComponents={{
          Button,
          Card,
          DropdownMenu,
          Form,
          Input,
          Label,
          Popover,
          Tabs,
          Toggle,
          Tooltip,
        }}
      />

      <Displayfile fileList={fileList} setFileList={setFileList} />
      <div className="flex justify-between">
        <Emoji />
        <Uploadfile setFileList={setFileList} />
      </div>
    </div>
  );
};

export default Workspace;
bunnybunbun37204 commented 15 hours ago
  useEffect(() => {
    const loadInitialHTML = async () => {
      try {
        const blocks = await editor.tryParseHTMLToBlocks(TexteditList?.description || '');
        editor.replaceBlocks(editor.document, blocks);
      } catch (error) {
        console.error("Failed to load initial HTML:", error);
      }
    };

    loadInitialHTML();
  }, [editor, TexteditList]);

try this instead hope it will work

bypkt-bk commented 12 hours ago

Use useref