Skip to content

Commit

Permalink
Merge pull request #152 from Alforoan/upload-download-temp
Browse files Browse the repository at this point in the history
upload and download frontend
  • Loading branch information
JeremySpence272 authored Jul 2, 2024
2 parents b2bf78b + a856169 commit e7f4dbc
Show file tree
Hide file tree
Showing 10 changed files with 376 additions and 40 deletions.
21 changes: 18 additions & 3 deletions client/src/components/DownloadTemplateComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@

import React, { useEffect, useState } from "react";
import { useBoard } from "../context/BoardContext";
import { Board } from "../types";
import { v4 as uuidv4 } from "uuid";
import { useTemplates } from "../context/TemplateContext";

const DownloadTemplateComponent = () => {
const { selectedBoard } = useBoard();
const { selectedBoard, handleDownloadTemplate } = useBoard();
const { setIsTemplate } = useTemplates();
const [templateToDownload, setTemplateToDownload] = useState<Board>(
selectedBoard!
);

const handleDownloadTemplate = () => {
const handlePressDownload = () => {
console.log(selectedBoard!.name);
setTemplateToDownload((prevBoard) => ({
...prevBoard,
uuid: uuidv4(),
}));
handleDownloadTemplate(templateToDownload);
setIsTemplate(false);
};
return (
<div className="flex">
<button
onClick={handleDownloadTemplate}
onClick={handlePressDownload}
className="bg-secondaryElements text-primaryText px-4 py-2 rounded font-primary hover:text-primaryTextLighter"
>
Download
Expand Down
36 changes: 32 additions & 4 deletions client/src/components/SearchGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,47 @@ import {
htmlTemplate,
internetTemplate,
jsTemplate,
newCard,
} from "../dummyData";
import TemplatePreview from "./TemplatePreview";
import { Template } from "../types";
import useGetAllTemplates from "../hooks/useGetAllTemplates";
import useGetTemplateCards from "../hooks/useGetTemplateCards";

const allTemplates = [internetTemplate, htmlTemplate, cssTemplate, jsTemplate];
const dummyTemplates = [
internetTemplate,
htmlTemplate,
cssTemplate,
jsTemplate,
];

const SearchGrid = () => {
const { templateQuery } = useTemplates();
const [templates, setTemplates] = useState<Template[]>(allTemplates);
const [templates, setTemplates] = useState<Template[]>([]);
const [allTemplates, setAllTemplates] = useState<Template[]>(dummyTemplates);

const { getAllTemplates } = useGetAllTemplates();
const { getCardsFromTemplate } = useGetTemplateCards();

useEffect(() => {
console.log(`SEARCHING for ${templateQuery}`);
});
const fetchTemplates = async () => {
const templatesFromAPI = await getAllTemplates();

const updatedTemplates = await Promise.all(
templatesFromAPI.map(async (template) => {
const cardsFromAPI = await getCardsFromTemplate(template.uuid);
const updatedCards = [...cardsFromAPI, newCard];
return { ...template, cards: updatedCards };
})
);
setAllTemplates(updatedTemplates);
};

if (templates.length === 0) {
// UNCOMMENT WHEN ROUTE IS UP FOR GET ALL TEMPLATES AND GET CARDS FROM TEMPLATE
// fetchTemplates();
}
}, []);

useEffect(() => {
console.log(templates);
Expand Down
32 changes: 32 additions & 0 deletions client/src/components/UploadBoardComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { useState } from "react";
import { useBoard } from "../context/BoardContext";
import { useTemplates } from "../context/TemplateContext";
import { v4 as uuidv4 } from "uuid";

const UploadBoardComponent = () => {
const { selectedBoard } = useBoard();
const [boardName, setBoardName] = useState(selectedBoard!.name);
const { handleUploadNewTemplate } = useTemplates();

const handleClickUpload = () => {
console.log(selectedBoard?.name);
// THIS SHOULD POP UP MODAL TO CONFIRM WITH AN OPPORTUNITY TO CHANGE BOARD NAME
// TOAST SUCCESS NEEDED AFTER UPLOAD
const boardToUpload = {
...selectedBoard!,
name: boardName,
uuid: uuidv4(),
};
handleUploadNewTemplate(boardToUpload);
};
return (
<button
onClick={handleClickUpload}
className="bg-flair text-white px-4 py-2 rounded font-primary"
>
Upload
</button>
);
};

export default UploadBoardComponent;
38 changes: 26 additions & 12 deletions client/src/context/BoardContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ interface BoardContextType {
populateDummyData: () => void;
isToastSuccess: string;
setIsToastSuccess: (isToastSuccess: string) => void;

handleDownloadTemplate: (board: Board) => void;
}

// Create the context with a default undefined value
Expand All @@ -53,7 +53,7 @@ export const BoardProvider = ({ children }: { children: ReactNode }) => {
const { postNewBoard } = usePostNewBoard();
const { editCard } = useEditCard();
const { deleteCard } = useDeleteCard();
const [isToastSuccess, setIsToastSuccess] = useState<string>('');
const [isToastSuccess, setIsToastSuccess] = useState<string>("");

const updateTitleText = () => {
if (selectedCard) {
Expand Down Expand Up @@ -91,6 +91,19 @@ export const BoardProvider = ({ children }: { children: ReactNode }) => {
setSelectedBoard(updatedBoard);
};

const handleDownloadTemplate = async (board: Board) => {
await postNewBoard(board);
const newBoards = [...userBoards, board];
setUserBoards(newBoards);

board.cards!.forEach((card) => {
postNewCard(card, board!.uuid!);
});

board.cards?.unshift(newCard);
setSelectedBoard(null);
};

const handleUpdateCard = async (newCard: Card) => {
if (newCard.id !== "0") {
if (selectedBoard) {
Expand Down Expand Up @@ -135,7 +148,7 @@ export const BoardProvider = ({ children }: { children: ReactNode }) => {
}
};

const populateDummyData = () => {
const populateDummyData = async () => {
const dummyCardLists = [
sortingCards,
databaseCards,
Expand All @@ -150,21 +163,21 @@ export const BoardProvider = ({ children }: { children: ReactNode }) => {
"Mobile App Development",
];

dummyCardLists.forEach((list, i) => {
for (let i = 0; i < dummyCardLists.length; i++) {
let list = dummyCardLists[i];
let uuid1 = uuidv4();
const dummyBoard: Board = {
name: dummyBoardTitles[i],
uuid: uuid1,
cards: list,
};
postNewBoard(dummyBoard);
dummyBoard.cards?.forEach((card) => {
postNewCard(card, uuid1);
});
await postNewBoard(dummyBoard);
for (let i = 0; i < dummyBoard.cards!.length; i++) {
await postNewCard(dummyBoard.cards![i], uuid1);
}
dummyBoard.cards?.unshift(newCard);
const newBoards = [...userBoards, dummyBoard];
setUserBoards(newBoards);
});
setUserBoards((prev) => [...prev, dummyBoard]);
}
};

return (
Expand All @@ -187,7 +200,8 @@ export const BoardProvider = ({ children }: { children: ReactNode }) => {
handleUpdateCard,
populateDummyData,
isToastSuccess,
setIsToastSuccess
setIsToastSuccess,
handleDownloadTemplate,
}}
>
{children}
Expand Down
27 changes: 27 additions & 0 deletions client/src/context/TemplateContext.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { createContext, useState, useContext, ReactNode } from "react";

import { Board } from "../types";
import usePostNewTemplate from "../hooks/usePostNewTemplate";
import usePostTemplateCard from "../hooks/usePostTemplateCard";


// Define the context shape
interface TemplateContextType {
templateQuery: string;
Expand All @@ -9,6 +14,9 @@ interface TemplateContextType {
isSearching: boolean;
isTemplate: boolean;
setIsTemplate: (isTemplate: boolean) => void;
handleUploadNewTemplate: (template: Board) => void;
uploadedTemplateNames: string[];
setUploadedTemplateNames: (names: string[]) => void;
}

const TemplateContext = createContext<TemplateContextType | undefined>(
Expand All @@ -19,6 +27,12 @@ export const TemplateProvider = ({ children }: { children: ReactNode }) => {
const [templateQuery, setTemplateQuery] = useState<string>("");
const [isSearching, setIsSearching] = useState<boolean>(false);
const [isTemplate, setIsTemplate] = useState<boolean>(false);
const [uploadedTemplateNames, setUploadedTemplateNames] = useState<string[]>(
[]
);

const { postNewTemplate } = usePostNewTemplate();
const { postTemplateCard } = usePostTemplateCard();

const handleUpdateSearchQuery = (query: string) => {
setTemplateQuery(query);
Expand All @@ -28,6 +42,16 @@ export const TemplateProvider = ({ children }: { children: ReactNode }) => {
setIsSearching((prev) => !prev);
};

const handleUploadNewTemplate = (template: Board) => {
// UNCOMMENT WHEN ROUTE IS COMPLETED. MAY NEED ASYNC/AWAIT IF ISSUES UPLOADING ALL AT ONCE
// postNewTemplate(template);
// template.cards!.forEach((card) => {
// postTemplateCard(card, template.uuid);
// });

setUploadedTemplateNames((prev) => [...prev, template.name]);
};

return (
<TemplateContext.Provider
value={{
Expand All @@ -38,6 +62,9 @@ export const TemplateProvider = ({ children }: { children: ReactNode }) => {
isSearching,
setIsTemplate,
isTemplate,
handleUploadNewTemplate,
uploadedTemplateNames,
setUploadedTemplateNames,
}}
>
{children}
Expand Down
43 changes: 43 additions & 0 deletions client/src/hooks/useGetAllTemplates.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useState } from "react";
import axios from "axios";
import { Template } from "../types"; // Ensure Card is also imported if it's a separate type

const useGetAllTemplates = () => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<Error | null>(null);

const getAllTemplates = async (): Promise<Template[]> => {
setIsLoading(true);
setError(null);
try {
const response = await axios.get(
`${import.meta.env.VITE_BACKEND_URL}/api/templates`
);
setIsLoading(false);
const templates: Template[] = response.data.map(
(datapt: { [x: string]: any }) => {
let template: Template = {
uuid: datapt["uuid"],
name: datapt["name"],
downloads: datapt["downloads"],
author: datapt["author"],
cards: [],
};

return template;
}
);
return templates;
} catch (err) {
if (err instanceof Error) {
setError(err);
setIsLoading(false);
}
return [];
}
};

return { getAllTemplates, isLoading, error };
};

export default useGetAllTemplates;
52 changes: 52 additions & 0 deletions client/src/hooks/useGetTemplateCards.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { useState } from "react";
import axios from "axios";
import { Card, CardDetails, ChecklistEntry, Columns } from "../types"; // Ensure Card is also imported if it's a separate type

const useGetTemplateCards = () => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<Error | null>(null);

const getCardsFromTemplate = async (boardId: string): Promise<Card[]> => {
setIsLoading(true);
setError(null);

try {
const response = await axios.get(
`${import.meta.env.VITE_BACKEND_URL}/api/templates/${boardId}`
);
setIsLoading(false);

const cards = response.data.map((datapt: { [x: string]: any }) => {
let details = JSON.parse(datapt["details"]);
const cardDetails: CardDetails = {
checklist: details["checklist"] as ChecklistEntry[],
notes: details["notes"],
timeEstimate: details["timeEstimate"],
};

let card: Card = {
id: datapt["card_id"],
cardName: datapt["card_name"],
column: datapt["column_name"] as Columns,
creationDate: datapt["creation_date"] as Date,
order: datapt["order"],
details: cardDetails,
};

return card;
});

return cards;
} catch (err) {
if (err instanceof Error) {
setError(err);
setIsLoading(false);
}
return [];
}
};

return { getCardsFromTemplate, isLoading, error };
};

export default useGetTemplateCards;
Loading

0 comments on commit e7f4dbc

Please sign in to comment.