Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vertical content cards #2470

Merged
merged 31 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
fa030bc
new branch
GiseleN523 Jun 16, 2024
2298cfb
Delete client/public/doenetml-worker directory
GiseleN523 Jun 21, 2024
cfd50c8
Merge branch 'Doenet:main' into main
GiseleN523 Jul 1, 2024
b3fd704
Merge branch 'main' of https://github.com/Doenet/DoenetTools into ver…
GiseleN523 Aug 2, 2024
cdaaf48
option in activities to toggle between activity card view and list view
GiseleN523 Aug 8, 2024
5f759b1
Merge remote-tracking branch 'upstream/main' into verticalContentCards
GiseleN523 Aug 12, 2024
b84a645
assignment status column in Assignments page, people icon moved to th…
GiseleN523 Aug 13, 2024
609f2c4
Merge branch 'main' into verticalContentCards
dqnykamp Aug 13, 2024
61bc303
get and set preferred folder view
dqnykamp Aug 13, 2024
d8fbedd
fix tests
dqnykamp Aug 13, 2024
1e20024
button in community to toggle list/card view
GiseleN523 Aug 13, 2024
f3d0005
Merge branch 'verticalContentCards' of https://github.com/GiseleN523/…
GiseleN523 Aug 13, 2024
e919a32
Merge pull request #3 from dqnykamp/preferredFolderView
GiseleN523 Aug 13, 2024
0beacf8
Merge branch 'verticalContentCards' of https://github.com/GiseleN523/…
GiseleN523 Aug 13, 2024
f8b4c91
list view for community and assigned pages
GiseleN523 Aug 14, 2024
f891bc0
fixed folders that continue to be selected even when user clicks away
GiseleN523 Aug 14, 2024
aae7a8f
show author results in community list mode and center cards
GiseleN523 Aug 14, 2024
274851a
fixed icon for author row in community results
GiseleN523 Aug 14, 2024
3dcc631
fixed scroll amounts in community, activities, assigned
GiseleN523 Aug 14, 2024
7b09d6b
remembering user's last preference for list vs card view
GiseleN523 Aug 14, 2024
557a90a
made editable text appear as normal clickable text when editableTitle…
GiseleN523 Aug 14, 2024
c700c93
ran prettier because I forgot earlier
GiseleN523 Aug 14, 2024
822b5af
get/set preferred view doesn't crash when not logged in
dqnykamp Aug 15, 2024
93c2bb4
fix server lints
dqnykamp Aug 15, 2024
69f105b
made background blue regardless of list/card view when there is no co…
GiseleN523 Aug 15, 2024
473a054
Merge branch 'verticalContentCards' of https://github.com/GiseleN523/…
GiseleN523 Aug 15, 2024
3a53dbd
prevents clicking behavior while title is in edit mode (really just h…
GiseleN523 Aug 16, 2024
f8ec4d9
activitytable for narrow screens and improved appearance of very long…
GiseleN523 Aug 17, 2024
2784c26
Fix regression in changing content name from #2472
dqnykamp Aug 19, 2024
b197397
Merge pull request #4 from dqnykamp/verticalContentCards
GiseleN523 Aug 19, 2024
97988ec
removed extra spaces causing errors
GiseleN523 Aug 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
409 changes: 269 additions & 140 deletions client/src/Tools/_framework/Paths/Activities.tsx

Large diffs are not rendered by default.

306 changes: 208 additions & 98 deletions client/src/Tools/_framework/Paths/Assigned.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,127 @@
// import axios from 'axios';
import { Button, Box, Icon, Text, Flex, Wrap, Heading } from "@chakra-ui/react";
import React, { useEffect } from "react";
import {
Button,
Box,
Icon,
Text,
Flex,
Wrap,
Heading,
ButtonGroup,
Tooltip,
VStack,
HStack,
} from "@chakra-ui/react";
import React, { useEffect, useState } from "react";
import { useLoaderData, useNavigate, useFetcher } from "react-router-dom";

import { RiEmotionSadLine } from "react-icons/ri";
import { FaListAlt, FaRegListAlt } from "react-icons/fa";
import { IoGrid, IoGridOutline } from "react-icons/io5";
import ContentCard from "../../../Widgets/ContentCard";
import axios from "axios";
import { createFullName } from "../../../_utils/names";
import { ContentStructure } from "./ActivityEditor";
import { DateTime } from "luxon";
import ActivityTable from "../../../Widgets/ActivityTable";

export async function action({ request }) {
const formData = await request.formData();
let formObj = Object.fromEntries(formData);

if (formObj?._action == "Set List View Preferred") {
await axios.post(`/api/setPreferredFolderView`, {
cardView: formObj.listViewPref === "false",
});
return true;
}

throw Error(`Action "${formObj?._action}" not defined or not handled.`);
}

export async function loader({ params }) {
const { data: assignmentData } = await axios.get(`/api/getAssigned`);

let prefData = await axios.get(`/api/getPreferredFolderView`);
let listViewPref = !prefData.data.cardView;

return {
user: assignmentData.user,
assignments: assignmentData.assignments,
listViewPref,
};
}

export function Assigned() {
let { user, assignments } = useLoaderData() as {
let { user, assignments, listViewPref } = useLoaderData() as {
user: {
userId: number;
firstNames: string | null;
lastNames: string;
};
assignments: ContentStructure[];
listViewPref: Boolean;
};

const navigate = useNavigate();
const fetcher = useFetcher();

const [listView, setListView] = useState(listViewPref);

useEffect(() => {
document.title = `Assigned - Doenet`;
}, []);

const fetcher = useFetcher();
function formatTime(time: string | null) {
let timeFormatted: string | undefined;

if (time !== null) {
const sameDay = (a: DateTime, b: DateTime): boolean => {
return (
a.hasSame(b, "day") && a.hasSame(b, "month") && a.hasSame(b, "year")
);
};

let closeDateTime = DateTime.fromISO(time);
let now = DateTime.now();
let tomorrow = now.plus({ day: 1 });

if (sameDay(closeDateTime, now)) {
if (closeDateTime.minute === 0) {
timeFormatted = `today, ${closeDateTime.toLocaleString({ hour: "2-digit" })}`;
} else {
timeFormatted = `today, ${closeDateTime.toLocaleString({ hour: "2-digit", minute: "2-digit" })}`;
}
} else if (sameDay(closeDateTime, tomorrow)) {
if (closeDateTime.minute === 0) {
timeFormatted = `tomorrow, ${closeDateTime.toLocaleString({ hour: "2-digit" })}`;
} else {
timeFormatted = `tomorrow, ${closeDateTime.toLocaleString({ hour: "2-digit", minute: "2-digit" })}`;
}
} else if (closeDateTime.year === now.year) {
if (closeDateTime.minute === 0) {
timeFormatted = closeDateTime.toLocaleString({
weekday: "short",
month: "short",
day: "numeric",
hour: "2-digit",
});
} else {
timeFormatted = closeDateTime.toLocaleString({
weekday: "short",
month: "short",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
});
}
} else {
timeFormatted = closeDateTime.toLocaleString(DateTime.DATETIME_MED);
}
}

return timeFormatted;
}

return (
<>
Expand All @@ -45,110 +131,134 @@ export function Assigned() {
height="80px"
width="100%"
textAlign="center"
padding=".5em 0"
>
<Heading as="h2" size="lg">
{createFullName(user)}
</Heading>
<Heading as="h3" size="md">
Assigned Activities
</Heading>
<div style={{ float: "right", marginTop: "-10px" }}>
<Button
margin="3px"
size="xs"
colorScheme="blue"
onClick={() => navigate(`/code`)}
>
Class code
</Button>
<Button
margin="3px"
size="xs"
colorScheme="blue"
onClick={() => navigate(`/assignedData`)}
<VStack align="flex-end" float="right" marginRight=".5em">
<HStack>
<Button
size="sm"
colorScheme="blue"
onClick={() => navigate(`/code`)}
>
Class code
</Button>
<Button
size="sm"
colorScheme="blue"
onClick={() => navigate(`/assignedData`)}
>
See Scores
</Button>
</HStack>
<ButtonGroup
size="sm"
isAttached
variant="outline"
marginBottom=".5em"
>
See Scores
</Button>
</div>
<Tooltip label="Toggle List View">
<Button isActive={listView === true}>
<Icon
as={listView ? FaListAlt : FaRegListAlt}
boxSize={10}
p=".5em"
cursor="pointer"
onClick={() => {
if (listView === false) {
setListView(true);
fetcher.submit(
{
_action: "Set List View Preferred",
listViewPref: true,
},
{ method: "post" },
);
}
}}
/>
</Button>
</Tooltip>
<Tooltip label="Toggle Card View">
<Button isActive={listView === false}>
<Icon
as={listView ? IoGridOutline : IoGrid}
boxSize={10}
p=".5em"
cursor="pointer"
onClick={() => {
if (listView === true) {
setListView(false);
fetcher.submit(
{
_action: "Set List View Preferred",
listViewPref: false,
},
{ method: "post" },
);
}
}}
/>
</Button>
</Tooltip>
</ButtonGroup>
</VStack>
</Box>
<Flex
data-test="Assigned Activities"
padding="10px"
margin="0px"
padding=".5em 10px"
margin="0"
width="100%"
justifyContent="center"
background="var(--lightBlue)"
minHeight="calc(100vh - 120px)"
background={
listView && assignments.length > 0 ? "white" : "var(--lightBlue)"
}
minHeight="calc(100vh - 188px)"
flexDirection="column"
>
<Wrap p="10px" overflow="visible">
{assignments.length < 1 ? (
<Flex
flexDirection="column"
justifyContent="center"
alignItems="center"
alignContent="center"
minHeight={200}
background="doenet.canvas"
padding={20}
width="100%"
>
<Icon fontSize="48pt" as={RiEmotionSadLine} />
<Text fontSize="36pt">Nothing Assigned</Text>
</Flex>
) : (
<>
{assignments.length < 1 ? (
<Flex
flexDirection="column"
justifyContent="center"
alignItems="center"
alignContent="center"
minHeight={200}
padding={20}
width="100%"
>
<Icon fontSize="48pt" as={RiEmotionSadLine} />
<Text fontSize="36pt">Nothing Assigned</Text>
</Flex>
) : listView ? (
<ActivityTable
suppressAvatar={true}
showPublicStatus={false}
showAssignmentStatus={true}
content={assignments.map((assignment) => {
return {
id: assignment.id,
title: assignment.name,
cardLink:
assignment.assignmentStatus === "Open"
? `/code/${assignment.classCode}`
: `/assignedData/${assignment.id}`,
assignmentStatus: assignment.assignmentStatus,
closeTime: formatTime(assignment.codeValidUntil),
};
})}
/>
) : (
<Flex
justifyContent="center"
alignItems="center"
alignContent="center"
>
<Wrap p="10px" overflow="visible">
{assignments.map((assignment) => {
let closes: string | undefined;
if (assignment.codeValidUntil !== null) {
const sameDay = (a: DateTime, b: DateTime): boolean => {
return (
a.hasSame(b, "day") &&
a.hasSame(b, "month") &&
a.hasSame(b, "year")
);
};

let closeDateTime = DateTime.fromISO(
assignment.codeValidUntil,
);
let now = DateTime.now();
let tomorrow = now.plus({ day: 1 });

if (sameDay(closeDateTime, now)) {
if (closeDateTime.minute === 0) {
closes = `today, ${closeDateTime.toLocaleString({ hour: "2-digit" })}`;
} else {
closes = `today, ${closeDateTime.toLocaleString({ hour: "2-digit", minute: "2-digit" })}`;
}
} else if (sameDay(closeDateTime, tomorrow)) {
if (closeDateTime.minute === 0) {
closes = `tomorrow, ${closeDateTime.toLocaleString({ hour: "2-digit" })}`;
} else {
closes = `tomorrow, ${closeDateTime.toLocaleString({ hour: "2-digit", minute: "2-digit" })}`;
}
} else if (closeDateTime.year === now.year) {
if (closeDateTime.minute === 0) {
closes = closeDateTime.toLocaleString({
weekday: "short",
month: "short",
day: "numeric",
hour: "2-digit",
});
} else {
closes = closeDateTime.toLocaleString({
weekday: "short",
month: "short",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
});
}
} else {
closes = closeDateTime.toLocaleString(
DateTime.DATETIME_MED,
);
}
}
return (
<ContentCard
key={`Card${assignment.id}`}
Expand All @@ -165,13 +275,13 @@ export function Assigned() {
showPublicStatus={false}
showAssignmentStatus={true}
assignmentStatus={assignment.assignmentStatus}
closeTime={closes}
closeTime={formatTime(assignment.codeValidUntil)}
/>
);
})}
</>
)}
</Wrap>
</Wrap>
</Flex>
)}
</Flex>
</>
);
Expand Down
Loading