From 827ec3c60a70352b896980b3ff56fa31765f851d Mon Sep 17 00:00:00 2001 From: amir_emami Date: Fri, 30 Aug 2024 17:49:07 +0530 Subject: [PATCH] Content snackbar and page 3 layout update (#419) * Remove content ID from snackbar messages * Add slide-in and clean disappear to snackbars on content page * Make content edit/creation snackbar independent of URL * Update to "Query Topics" and update logos * Refactor dashboard page 3 layout components * Hide AI summary box if discovery has never been run * Button now says Run Discovery if never ran, "Rerun" if ran before. Updated to LoadingButton with magic wand logo. --------- Co-authored-by: Mark Botterill --- admin_app/src/app/content/edit/page.tsx | 31 ++++++--- admin_app/src/app/content/page.tsx | 49 ++++++------- .../src/app/dashboard/components/Insights.tsx | 69 ++++++++++++------- .../src/app/dashboard/components/Sidebar.tsx | 10 +-- .../dashboard/components/insights/Queries.tsx | 41 ++++++----- .../dashboard/components/insights/Topics.tsx | 10 +-- admin_app/src/app/dashboard/page.tsx | 4 +- 7 files changed, 123 insertions(+), 91 deletions(-) diff --git a/admin_app/src/app/content/edit/page.tsx b/admin_app/src/app/content/edit/page.tsx index 31e3c79fd..4aba8a32f 100644 --- a/admin_app/src/app/content/edit/page.tsx +++ b/admin_app/src/app/content/edit/page.tsx @@ -160,6 +160,10 @@ const ContentBox = ({ const [highlightedOption, setHighlightedOption] = React.useState(); const [isSaving, setIsSaving] = React.useState(false); + const setMainPageSnackMessage = (message: string): void => { + localStorage.setItem("editPageSnackMessage", message); + }; + const router = useRouter(); React.useEffect(() => { const fetchTags = async () => { @@ -181,6 +185,7 @@ const ContentBox = ({ fetchTags(); }, [refreshKey]); + const saveContent = async (content: Content): Promise => { setIsSaving(true); @@ -215,6 +220,19 @@ const ContentBox = ({ setIsSaving(false); } }; + + const handleSaveContent = async (content: Content) => { + const content_id = await saveContent(content); + if (content_id) { + { + content.content_id + ? setMainPageSnackMessage("Content edited successfully") + : setMainPageSnackMessage("Content created successfully"); + } + router.push(`/content`); + } + }; + function createEmptyContent(contentTags: Tag[]): Content { return { content_id: null, @@ -228,6 +246,7 @@ const ContentBox = ({ content_metadata: {}, }; } + const handleChange = ( e: React.ChangeEvent, key: keyof Content, @@ -242,6 +261,7 @@ const ContentBox = ({ : setContent({ ...emptyContent, [key]: e.target.value }); setIsSaved(false); }; + const handleTagsChange = (updatedTags: Tag[]) => { setContentTags(updatedTags); setIsSaved(false); @@ -272,6 +292,7 @@ const ContentBox = ({ setSnackMessage(`Tag "${tag}" already exists`); } }; + const openDeleteConfirmModal = (tag: Tag) => { setTagToDelete(tag); setOpenDeleteModal(true); @@ -289,6 +310,7 @@ const ContentBox = ({ }); } }; + return ( { - const content_id = await saveContent(content); - if (content_id) { - const actionType = content.content_id ? "edit" : "add"; - router.push( - `/content/?content_id=${content_id}&action=${actionType}`, - ); - } - }; handleSaveContent(content); } }} diff --git a/admin_app/src/app/content/page.tsx b/admin_app/src/app/content/page.tsx index 0749d7ca7..9beaadb83 100644 --- a/admin_app/src/app/content/page.tsx +++ b/admin_app/src/app/content/page.tsx @@ -15,6 +15,8 @@ import { Menu, MenuItem, Paper, + Slide, + SlideProps, Snackbar, TextField, Tooltip, @@ -30,7 +32,7 @@ import type { Content } from "@/app/content/edit/page"; import ContentCard from "./components/ContentCard"; import { DownloadModal } from "./components/DownloadModal"; import { Layout } from "@/components/Layout"; -import { appStyles, appColors, LANGUAGE_OPTIONS, sizes } from "@/utils"; +import { appColors, LANGUAGE_OPTIONS, sizes } from "@/utils"; import { apiCalls } from "@/utils/api"; import { useAuth } from "@/utils/auth"; import { ImportModal } from "./components/ImportModal"; @@ -101,6 +103,10 @@ const CardsPage = () => { } }, [accessLevel, token]); + const SnackbarSlideTransition = (props: SlideProps) => { + return ; + }; + return ( <> @@ -205,10 +211,11 @@ const CardsPage = () => { { setSnackMessage({ message: null, color: snackMessage.color }); }} + TransitionComponent={SnackbarSlideTransition} > { @@ -414,8 +421,6 @@ const CardsGrid = ({ const [isLoading, setIsLoading] = React.useState(true); const searchParams = useSearchParams(); - const action = searchParams.get("action") || null; - const content_id = Number(searchParams.get("content_id")) || null; const calculateMaxCardsPerPage = () => { // set rows as per height of each card and height of grid (approximated from window height) @@ -445,33 +450,12 @@ const CardsGrid = ({ return () => window.removeEventListener("resize", calculateMaxCardsPerPage); }, []); - const getSnackMessage = React.useCallback( - (action: string | null, content_id: number | null): string | null => { - if (action === "edit") { - return `Content #${content_id} updated`; - } else if (action === "add") { - return `Content #${content_id} created`; - } - return null; - }, - [], - ); - - React.useEffect(() => { - if (action) { - setSnackMessage({ - message: getSnackMessage(action, content_id), - color: "success", - }); - } - }, [action, content_id, getSnackMessage]); - const [refreshKey, setRefreshKey] = React.useState(0); const onSuccessfulArchive = (content_id: number) => { setIsLoading(true); setRefreshKey((prevKey) => prevKey + 1); setSnackMessage({ - message: `Content #${content_id} removed successfully`, + message: `Content removed successfully`, color: "success", }); }; @@ -479,7 +463,7 @@ const CardsGrid = ({ setIsLoading(true); setRefreshKey((prevKey) => prevKey + 1); setSnackMessage({ - message: `Content #${content_id} deleted successfully`, + message: `Content deleted successfully`, color: "success", }); }; @@ -504,6 +488,15 @@ const CardsGrid = ({ setCards(filteredData); setMaxPages(Math.ceil(filteredData.length / maxCardsPerPage)); setIsLoading(false); + + const message = localStorage.getItem("editPageSnackMessage"); + if (message) { + setSnackMessage({ + message: message, + color: "success", + }); + localStorage.removeItem("editPageSnackMessage"); + } }) .catch((error) => { console.error("Failed to fetch content:", error); @@ -618,7 +611,7 @@ const CardsGrid = ({ onSuccessfulArchive={onSuccessfulArchive} onFailedArchive={(content_id: number) => { setSnackMessage({ - message: `Failed to remove content #${content_id}`, + message: `Failed to remove content`, color: "error", }); }} diff --git a/admin_app/src/app/dashboard/components/Insights.tsx b/admin_app/src/app/dashboard/components/Insights.tsx index ea340db7f..cd19e1e28 100644 --- a/admin_app/src/app/dashboard/components/Insights.tsx +++ b/admin_app/src/app/dashboard/components/Insights.tsx @@ -7,6 +7,7 @@ import { useState } from "react"; import { QueryData, Period, TopicModelingResponse } from "../types"; import { generateNewTopics, fetchTopicsData } from "../api"; import { useAuth } from "@/utils/auth"; +import { Paper } from "@mui/material"; interface InsightProps { timePeriod: Period; @@ -76,25 +77,45 @@ const Insight: React.FC = ({ timePeriod }) => { ); return ( - - + - - - + + = ({ timePeriod }) => { lastRefreshed={dataFromBackend.refreshTimeStamp} refreshing={refreshing} /> - - - + + = ({ timePeriod }) => { justifyContent: "center", }} > - -- Chart - Coming Soon! -- + Chart coming soon! - - + + ); }; diff --git a/admin_app/src/app/dashboard/components/Sidebar.tsx b/admin_app/src/app/dashboard/components/Sidebar.tsx index c471f9a8a..31973df48 100644 --- a/admin_app/src/app/dashboard/components/Sidebar.tsx +++ b/admin_app/src/app/dashboard/components/Sidebar.tsx @@ -1,11 +1,11 @@ import React from "react"; import { - BarChart, + Category, ChevronLeft, ChevronRight, Dashboard, - Insights, + QueryStats, } from "@mui/icons-material"; import { Box, @@ -27,7 +27,7 @@ interface SideBarProps { selectedDashboardPage: PageName; } -type PageName = "Overview" | "Content Performance" | "Content Gaps"; +type PageName = "Overview" | "Content Performance" | "Query Topics"; interface MenuItem { name: PageName; @@ -35,8 +35,8 @@ interface MenuItem { } const menuItems: MenuItem[] = [ { name: "Overview", icon: }, - { name: "Content Performance", icon: }, - { name: "Content Gaps", icon: }, + { name: "Content Performance", icon: }, + { name: "Query Topics", icon: }, ]; const openedMixin = (theme: Theme): CSSObject => ({ width: drawerWidth, diff --git a/admin_app/src/app/dashboard/components/insights/Queries.tsx b/admin_app/src/app/dashboard/components/insights/Queries.tsx index 72aab0f30..1e393e27c 100644 --- a/admin_app/src/app/dashboard/components/insights/Queries.tsx +++ b/admin_app/src/app/dashboard/components/insights/Queries.tsx @@ -1,17 +1,17 @@ -import React from "react"; +import { AutoFixHigh } from "@mui/icons-material"; +import AutoAwesomeIcon from "@mui/icons-material/AutoAwesome"; +import { LoadingButton } from "@mui/lab"; import { Box } from "@mui/material"; +import { grey, orange } from "@mui/material/colors"; import Table from "@mui/material/Table"; import TableBody from "@mui/material/TableBody"; import TableCell from "@mui/material/TableCell"; import TableContainer from "@mui/material/TableContainer"; import TableHead from "@mui/material/TableHead"; import TableRow from "@mui/material/TableRow"; -import { grey, orange } from "@mui/material/colors"; import Typography from "@mui/material/Typography"; -import AutoAwesomeIcon from "@mui/icons-material/AutoAwesome"; -import Button from "@mui/material/Button"; +import React from "react"; import { QueryData } from "../../types"; -import CircularProgress from "@mui/material/CircularProgress"; interface QueriesProps { data: QueryData[]; @@ -37,7 +37,7 @@ const AISummary: React.FC = ({ aiSummary }) => { borderRadius: 2, background: "linear-gradient(to bottom, rgba(176,198,255,0.5), #ffffff)", p: 2, - mb: 3, + mb: 1, }} > @@ -90,7 +90,7 @@ const Queries: React.FC = ({ display: "flex", flexDirection: "row", justifyContent: "space-between", - mb: 2, + mb: 1, }} > Example Queries @@ -106,30 +106,33 @@ const Queries: React.FC = ({ > Last run: {formattedLastRefreshed} - + {data.length > 0 ? "Rerun Discovery" : "Run Discovery"} + - + {data.length > 0 && } {data.length > 0 ? ( @@ -159,9 +162,9 @@ const Queries: React.FC = ({ ) : ( - - No queries found. Please re-run discovery - + + Click "Run Discovery" to generate insights for this time period. + )} diff --git a/admin_app/src/app/dashboard/components/insights/Topics.tsx b/admin_app/src/app/dashboard/components/insights/Topics.tsx index a7e73e41b..7d4d5db38 100644 --- a/admin_app/src/app/dashboard/components/insights/Topics.tsx +++ b/admin_app/src/app/dashboard/components/insights/Topics.tsx @@ -1,5 +1,5 @@ import React, { useEffect } from "react"; -import { Box } from "@mui/material"; +import { Box, Typography } from "@mui/material"; import Chip from "@mui/material/Chip"; import ListItemButton from "@mui/material/ListItemButton"; import { orange } from "@mui/material/colors"; @@ -43,11 +43,13 @@ const Topics: React.FC = ({ display: "flex", flexDirection: "column", justifyContent: "space-between", - height: 350, + height: "100%", }} > - Topics + + Topics + {dataToShow.map((topic) => ( = ({ justifyContent: "space-between", borderRadius: 2, my: 0.5, - ml: -0.5, + marginLeft: -0.5, }} > {topic.topic_name} diff --git a/admin_app/src/app/dashboard/page.tsx b/admin_app/src/app/dashboard/page.tsx index 82b795250..db0432e96 100644 --- a/admin_app/src/app/dashboard/page.tsx +++ b/admin_app/src/app/dashboard/page.tsx @@ -26,7 +26,7 @@ const pages: Page[] = [ description: "Track performance of contents and identify areas for improvement", }, { - name: "Content Gaps", + name: "Query Topics", description: "Find out what users are asking about to inform creating and updating contents", }, @@ -47,7 +47,7 @@ const Dashboard: React.FC = () => { return ; case "Content Performance": return ; - case "Content Gaps": + case "Query Topics": return ; default: return
Page not found.
;