From ca8efc22abf2f6732dc58ee89f404e3cf3ff1ee9 Mon Sep 17 00:00:00 2001 From: hugosandsjo Date: Tue, 17 Sep 2024 11:48:03 +0200 Subject: [PATCH] fixed feedback --- backend/.env.development | 4 +- backend/docker/docker-compose-full.yml | 4 +- .../workspace-documents.controller.ts | 11 +- .../workspace-documents.service.ts | 14 +- .../src/components/headers/DocumentHeader.tsx | 120 ++++++++++-------- frontend/src/hooks/api/workspaceDocument.ts | 2 +- 6 files changed, 87 insertions(+), 68 deletions(-) diff --git a/backend/.env.development b/backend/.env.development index 8c8d82a1..3ad57c10 100644 --- a/backend/.env.development +++ b/backend/.env.development @@ -5,10 +5,10 @@ DATABASE_URL=mongodb://localhost:27017/codepair # GITHUB_CLIENT_ID: Client ID for authenticating with GitHub. # To obtain a client ID, create an OAuth app at: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app -GITHUB_CLIENT_ID=your_github_client_id_here +GITHUB_CLIENT_ID=Iv23li1CysRsALb97SET # GITHUB_CLIENT_SECRET: Client secret for authenticating with GitHub. # To obtain a client ID, create an OAuth app at: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app -GITHUB_CLIENT_SECRET=your_github_client_secret_here +GITHUB_CLIENT_SECRET=55d8a3062aebb7fc25af27930d8556506930b67f # GITHUB_CALLBACK_URL: Callback URL for handling GitHub authentication response. # Format: https:///auth/login/github # Example: http://localhost:3000/auth/login/github (For development mode) diff --git a/backend/docker/docker-compose-full.yml b/backend/docker/docker-compose-full.yml index a42dc14e..1af40757 100644 --- a/backend/docker/docker-compose-full.yml +++ b/backend/docker/docker-compose-full.yml @@ -7,8 +7,8 @@ services: environment: DATABASE_URL: "mongodb://mongo:27017/codepair" # Environment variables need to be passed to the container - GITHUB_CLIENT_ID: "your_github_client_id_here" - GITHUB_CLIENT_SECRET: "your_github_client_secret_here" + GITHUB_CLIENT_ID: "Iv23li1CysRsALb97SET" + GITHUB_CLIENT_SECRET: "55d8a3062aebb7fc25af27930d8556506930b67f" GITHUB_CALLBACK_URL: "http://localhost:3000/auth/login/github" JWT_AUTH_SECRET: "you_should_change_this_secret_key_in_production" FRONTEND_BASE_URL: "http://localhost:5173" diff --git a/backend/src/workspace-documents/workspace-documents.controller.ts b/backend/src/workspace-documents/workspace-documents.controller.ts index e0cb189c..694e199b 100644 --- a/backend/src/workspace-documents/workspace-documents.controller.ts +++ b/backend/src/workspace-documents/workspace-documents.controller.ts @@ -38,8 +38,7 @@ import { FindWorkspaceDocumentResponse } from "./types/find-workspace-document-r export class WorkspaceDocumentsController { constructor(private workspaceDocumentsService: WorkspaceDocumentsService) {} - // PUT endpoint for updating document title - @Put(":document_id/title") + @Put(":document_id") @ApiOperation({ summary: "Update the title of a document in the workspace", description: "If the user has the access permissions, update the document's title.", @@ -69,8 +68,6 @@ export class WorkspaceDocumentsController { updateDocumentTitleDto.title ); } - - // Get the list of documents in the workspace @Get("") @ApiOperation({ summary: "Retrieve the Documents in Workspace", @@ -102,8 +99,6 @@ export class WorkspaceDocumentsController { ): Promise { return this.workspaceDocumentsService.findMany(req.user.id, workspaceId, pageSize, cursor); } - - // Get a specific document by ID @Get(":document_id") @ApiOperation({ summary: "Retrieve a Document in the Workspace", @@ -122,8 +117,6 @@ export class WorkspaceDocumentsController { ): Promise { return this.workspaceDocumentsService.findOne(req.user.id, workspaceId, documentId); } - - // Create a new document in the workspace @Post() @ApiOperation({ summary: "Create a Document in a Workspace", @@ -146,8 +139,6 @@ export class WorkspaceDocumentsController { createWorkspaceDocumentDto.title ); } - - // Generate a share token for a document @Post(":document_id/share-token") @ApiOperation({ summary: "Retrieve a Share Token for the Document", diff --git a/backend/src/workspace-documents/workspace-documents.service.ts b/backend/src/workspace-documents/workspace-documents.service.ts index d6152a4a..6a071736 100644 --- a/backend/src/workspace-documents/workspace-documents.service.ts +++ b/backend/src/workspace-documents/workspace-documents.service.ts @@ -23,6 +23,19 @@ export class WorkspaceDocumentsService { documentId: string, title: string ): Promise { + try { + await this.prismaService.userWorkspace.findFirstOrThrow({ + where: { + userId, + workspaceId, + }, + }); + } catch (e) { + throw new NotFoundException( + "The workspace does not exist, or the user lacks the appropriate permissions." + ); + } + const document = await this.prismaService.document.findFirst({ where: { id: documentId, @@ -34,7 +47,6 @@ export class WorkspaceDocumentsService { throw new NotFoundException("Document not found"); } - // Update the document's title await this.prismaService.document.update({ where: { id: documentId }, data: { title: title }, diff --git a/frontend/src/components/headers/DocumentHeader.tsx b/frontend/src/components/headers/DocumentHeader.tsx index 6e975bee..acbc8194 100644 --- a/frontend/src/components/headers/DocumentHeader.tsx +++ b/frontend/src/components/headers/DocumentHeader.tsx @@ -13,10 +13,11 @@ import { Tooltip, Button, FormControl, + Typography, } from "@mui/material"; import { useEffect, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; -import { useNavigate, useParams } from "react-router-dom"; +import { useNavigate } from "react-router-dom"; import { useUserPresence } from "../../hooks/useUserPresence"; import { EditorModeType, selectEditor, setMode } from "../../store/editorSlice"; import { selectWorkspace } from "../../store/workspaceSlice"; @@ -25,34 +26,25 @@ import ShareButton from "../common/ShareButton"; import ThemeButton from "../common/ThemeButton"; import UserPresenceList from "./UserPresenceList"; import { FormContainer, TextFieldElement } from "react-hook-form-mui"; -import { useGetWorkspaceQuery } from "../../hooks/api/workspace"; - -import { - useUpdateDocumentTitleMutation, - useGetDocumentQuery, -} from "../../hooks/api/workspaceDocument"; +import { selectDocument, setDocumentData } from "../../store/documentSlice"; +import { useUpdateDocumentTitleMutation } from "../../hooks/api/workspaceDocument"; +import { UpdateDocumentRequest } from "../../hooks/api/types/document"; function DocumentHeader() { const dispatch = useDispatch(); const navigate = useNavigate(); const editorState = useSelector(selectEditor); const workspaceState = useSelector(selectWorkspace); + const documentStore = useSelector(selectDocument); const { presenceList } = useUserPresence(editorState.doc); const [focused, setFocused] = useState(false); - const [documentTitle, setDocumentTitle] = useState(""); - const params = useParams(); - const { data: workspace } = useGetWorkspaceQuery(params.workspaceSlug); - - const { data: documentData } = useGetDocumentQuery( - workspace?.id || "", - params.documentId || "" - ); - const { mutateAsync: updateDocumentTitle } = useUpdateDocumentTitleMutation( - workspace?.id || "", - params.documentId || "" + workspaceState.data?.id || "", + documentStore.data?.id || "" ); + const isEditingDisabled = editorState.shareRole === "READ"; + const handleFocus = () => { setFocused(true); }; @@ -75,19 +67,32 @@ function DocumentHeader() { const handleDocumentTitleChange = ( e: React.ChangeEvent ) => { - setDocumentTitle(e.target.value); + if (documentStore.data) { + dispatch( + setDocumentData({ + ...documentStore.data, + title: e.target.value, + }) + ); + } }; - const handleUpdateDocumentTitle = async (data: { title: string }) => { + const handleUpdateDocumentTitle = async (data: UpdateDocumentRequest) => { + console.log(data); await updateDocumentTitle(data); setFocused(false); }; - useEffect(() => { - if (documentData && documentData.title) { - setDocumentTitle(documentData.title); - } - }, [documentData]); + const validationRules = { + required: "Title is required", + maxLength: { + value: 255, + message: "Title must be less than 255 characters", + }, + validate: { + notEmpty: (value: string) => value.trim() !== "" || "Title cannot be just whitespace", + }, + }; return ( @@ -128,34 +133,45 @@ function DocumentHeader() { )} - - - - - - {focused && ( - - )} - - - + {isEditingDisabled ? ( + {documentStore.data?.title} + ) : ( + + + + + {focused && ( + + )} + + + + )} diff --git a/frontend/src/hooks/api/workspaceDocument.ts b/frontend/src/hooks/api/workspaceDocument.ts index a1bd130b..e05e332c 100644 --- a/frontend/src/hooks/api/workspaceDocument.ts +++ b/frontend/src/hooks/api/workspaceDocument.ts @@ -114,7 +114,7 @@ export const useUpdateDocumentTitleMutation = (workspaceId: string, documentId: return useMutation({ mutationFn: async (data: UpdateDocumentRequest) => { const res = await axios.put( - `/workspaces/${workspaceId}/documents/${documentId}/title`, + `/workspaces/${workspaceId}/documents/${documentId}/`, data );