Skip to content
This repository has been archived by the owner on Dec 26, 2024. It is now read-only.

Commit

Permalink
Merge pull request #49 from Cassianky/client-angely-surveys
Browse files Browse the repository at this point in the history
[Admin] [Client] Surveys and Reviews
  • Loading branch information
ayangler authored Oct 31, 2023
2 parents 487a67c + d2375cc commit 8b236b8
Show file tree
Hide file tree
Showing 36 changed files with 3,286 additions and 9 deletions.
40 changes: 40 additions & 0 deletions admin-frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ import AdminNotificationPage from "./components/notification/AdminNotificationPa
import VerifyEmailPage from "./components/VerifyEmailPage";
import ViewActiveBookingsPage from "./components/booking/ViewActiveBookingsPage";
import ViewPastBookingsPage from "./components/booking/ViewPastBookingsPage";
import SubmittedSurvey from "./components/survey/SubmittedSurvey";
import SubmittedSurveys from "./components/survey/SubmittedSurveys";
import ActivityThemesPage from "./components/activitytheme/ActivityThemesPage";
import ActivityReviews from "./components/review/ActivityReviews";
import ManageReviewsForActivity from "./components/review/ManageReviewsForActivity";
import AdminChatpage from "./components/Chat/AdminChatPage";

function App() {
Expand Down Expand Up @@ -204,6 +208,42 @@ function App() {
</ProtectedRoute>
}
/>
<Route
exact
path="/surveys"
element={
<ProtectedRoute>
<SubmittedSurveys />
</ProtectedRoute>
}
/>
<Route
exact
path="/surveys/:surveyId"
element={
<ProtectedRoute>
<SubmittedSurvey />
</ProtectedRoute>
}
/>
<Route
exact
path="/reviews"
element={
<ProtectedRoute>
<ActivityReviews />
</ProtectedRoute>
}
/>
<Route
exact
path="/reviews/activity/:activityId"
element={
<ProtectedRoute>
<ManageReviewsForActivity />
</ProtectedRoute>
}
/>
<Route
exact
path="/verifyEmail/:token"
Expand Down
29 changes: 28 additions & 1 deletion admin-frontend/src/components/navbar/SideNavBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ const bookingManagementList = [
{ "View Active Bookings": "/viewActiveBookings" },
{ "View Past Bookings": "/viewPastBookings" },
];
const surveyManagementList = [
{ "View Submitted Surveys": "/surveys" },
{ "Manage Reviews": "/reviews" },
];

const StyledLink = styled(Link)`
text-decoration: none;
Expand Down Expand Up @@ -74,7 +78,6 @@ const SideNavBar = ({ isSidebarOpen }) => {
User Management
</Typography>
</Box>

<List>
{userManagementList.map((item, index) => (
<StyledDiv key={index}>
Expand Down Expand Up @@ -146,6 +149,30 @@ const SideNavBar = ({ isSidebarOpen }) => {
</ListItem>
</StyledLink>
))}
</List>{" "}
<Divider />
<Box sx={{ paddingLeft: 2, paddingTop: 2 }}>
<Typography
fontWeight={700}
color={theme.palette.primary.main}
fontSize={20}
>
Survey Management
</Typography>
</Box>
<List>
{surveyManagementList.map((item, index) => (
<StyledLink to={item[Object.keys(item)[0]]} key={index}>
<ListItem key={Object.keys(item)[0]} disablePadding>
<ListItemButton
selected={selectedItem === Object.keys(item)[0]}
onClick={() => handleItemClick(Object.keys(item)[0])}
>
<ListItemText primary={Object.keys(item)[0]} />
</ListItemButton>
</ListItem>
</StyledLink>
))}
</List>
</Box>
</Drawer>
Expand Down
54 changes: 54 additions & 0 deletions admin-frontend/src/components/review/ActivityReviews.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from "react";

import styled from "@emotion/styled";
import { useTheme } from "@emotion/react";
import { Badge, CircularProgress, Tabs, Tab, Typography } from "@mui/material";
import { useEffect, useState } from "react";
import {
useActivityStore,
useAdminSurveyResponseStore,
useBookingStore,
useSnackbarStore,
} from "../../zustand/GlobalStore";
import MainBodyContainer from "../common/MainBodyContainer";

import ReviewActivityTable from "./ReviewActivityTable";
function ActivityReviews() {
const theme = useTheme();

const { openSnackbar } = useSnackbarStore();
const { activities, getActivity, isLoading, pendingApprovalActivities } =
useActivityStore();

useEffect(() => {
const fetchData = async () => {
await getActivity();
};
fetchData();
}, [getActivity]);

if (isLoading) {
return <CircularProgress />;
}
return (
<MainBodyContainer
hasBackButton={false}
breadcrumbNames={[]}
breadcrumbLinks={[]}
currentBreadcrumbName={"Manage Reviews"}
>
<Typography
fontSize={25}
fontWeight={700}
noWrap
component="div"
color={theme.palette.primary.main}
>
Manage Reviews
</Typography>
{activities && <ReviewActivityTable activities={activities} />}
</MainBodyContainer>
);
}

export default ActivityReviews;
68 changes: 68 additions & 0 deletions admin-frontend/src/components/review/ManageReviewsForActivity.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React from "react";

import { useTheme } from "@emotion/react";
import { CircularProgress, Typography } from "@mui/material";
import { useEffect } from "react";
import { useParams } from "react-router-dom";
import {
useActivityStore,
useReviewStore,
useSnackbarStore
} from "../../zustand/GlobalStore";
import MainBodyContainer from "../common/MainBodyContainer";

import ManageReviewsForActivityTable from "./ManageReviewsForActivityTable";

function ManageReviewsForActivity() {
const theme = useTheme();
const { activityId } = useParams();

const { openSnackbar } = useSnackbarStore();
const { activities, getActivity, isLoading, pendingApprovalActivities } =
useActivityStore();

const { reviews, activity, getReviewsForActivity, toggleReviewVisibility } =
useReviewStore();

useEffect(() => {
const fetchData = async () => {
await getReviewsForActivity(activityId);
};
fetchData();
}, [getActivity]);
console.log(reviews);

const handleToggle = async (reviewId) => {
try {
await toggleReviewVisibility(reviewId);
console.log("after handle toggle", reviews)
} catch (error) {
console.error(error);
openSnackbar("An error occurred", "error");
}
};
if (isLoading) {
return <CircularProgress />;
}
return (
<MainBodyContainer
hasBackButton={true}
breadcrumbNames={["Manage Reviews"]}
breadcrumbLinks={["/reviews"]}
currentBreadcrumbName={`For ${activity?.title || "Loading"}`}
>
<Typography
fontSize={25}
fontWeight={700}
noWrap
component="div"
color={theme.palette.primary.main}
>
Manage Reviews For {activity?.title}
</Typography>
{reviews && <ManageReviewsForActivityTable reviews={reviews} handleToggle={handleToggle} />}
</MainBodyContainer>
);
}

export default ManageReviewsForActivity;
170 changes: 170 additions & 0 deletions admin-frontend/src/components/review/ManageReviewsForActivityTable.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import {
Dialog,
DialogContent,
Rating,
Stack,
Switch,
Typography,
} from "@mui/material";

import Box from "@mui/material/Box";
import { DataGrid, GridToolbarFilterButton } from "@mui/x-data-grid";
import PropTypes from "prop-types";
import React, { useEffect, useState } from "react";

const ManageReviewsForActivityTable = ({ reviews, handleToggle }) => {
const [currentTabRows, setCurrentTabRows] = useState(reviews);
const [selectedReview, setSelectedReview] = useState(null);

useEffect(() => {
setCurrentTabRows(reviews);
}, [reviews]);

const columns = [
{
field: "rating",
headerName: "Rating",
flex: 1,
renderCell: (params) => {
const ratingValue = params.value;
return (
<Stack
direction="row"
spacing={1}
justifyContent="center"
alignItems="center"
>
<Rating name="read-only" value={ratingValue} readOnly />
<div>{ratingValue}</div>
</Stack>
);
},
},
{
field: "comment",
headerName: "Client Comment",
flex: 1,
},
{
field: "client",
headerName: "By Client",
flex: 1,
renderCell: (params) => {
return params.row.client.name;
},
},
{
field: "date",
headerName: "Date Submitted",
flex: 1,
renderCell: (params) => {
const date = new Date(params.value);
const formattedDate = date.toLocaleDateString(undefined, {
year: "2-digit",
month: "2-digit",
day: "2-digit",
});
const formattedTime = date.toLocaleTimeString(undefined, {
hour: "numeric",
minute: "numeric",
hour12: true,
});
return (
<div style={{ display: "flex" }}>
<Typography color="#9F91CC" fontSize={"0.875rem"}>
Submitted on&nbsp;
<span style={{ color: "black" }}>
{formattedDate} at {formattedTime}
</span>
</Typography>
</div>
);
},
},
{
field: "actions",
type: "actions",
flex: 1,
headerName: "Shown",
renderCell: (params) => {
const isChecked = !params.row.hidden;
return (
<div
style={{
display: "flex",
paddingTop: 3,
paddingBottom: 3,
alignItems: "center",
}}
>
<Switch
color="primary"
checked={isChecked}
onChange={() => handleToggle(params.row._id)}
/>
</div>
);
},
},
];

const handleRowClick = (params) => {
setSelectedReview(params.row);
};

const handleClose = () => {
setSelectedReview(null);
};

return (
<Box>
<div style={{ height: 500, width: "99%" }}>
<DataGrid
initialState={{
pagination: {
paginationModel: { pageSize: 25, page: 0 },
},
}}
getRowId={(row) => row._id}
rows={currentTabRows}
columns={columns}
slots={{
toolbar: GridToolbarFilterButton,
}}
disableRowSelectionOnClick
getRowHeight={() => "auto"}
onRowClick={handleRowClick}
sx={{
borderRadius: "10px",
boxShadow: "4px 4px 0px 0px rgb(159 145 204 / 40%)",
border: "none",
backgroundColor: "white",
"& .MuiDataGrid-cell:hover": {
cursor: "pointer",
},
}}
/>
</div>
<Dialog open={selectedReview !== null} onClose={handleClose} fullWidth>
<DialogContent>
{selectedReview && (
<div>
<Typography variant="h6">Rating:</Typography>
<Rating name="read-only" value={selectedReview.rating} readOnly />
<Typography variant="h6">Comment:</Typography>
<Typography>{selectedReview.comment}</Typography>
<Typography variant="h6">By:</Typography>
<Typography>{selectedReview.client.name}</Typography>
</div>
)}
</DialogContent>
</Dialog>
</Box>
);
};

ManageReviewsForActivityTable.propTypes = {
reviews: PropTypes.array.isRequired,
};

export default ManageReviewsForActivityTable;
Loading

0 comments on commit 8b236b8

Please sign in to comment.