Skip to content

Commit 40cd8ff

Browse files
committed
858: Added daterange popover
858: Fixed tests
1 parent f78a3cb commit 40cd8ff

File tree

3 files changed

+165
-79
lines changed

3 files changed

+165
-79
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { Flex, Tooltip } from "@mantine/core";
2+
import { IconClock } from "@tabler/icons-react";
3+
4+
interface DateRangeClockIconProps {
5+
label: string;
6+
testId?: string;
7+
}
8+
9+
export function DateRangeClockIcon({
10+
label,
11+
testId = "date-range-clock-icon-mobile",
12+
}: DateRangeClockIconProps) {
13+
return (
14+
<Tooltip label={label} withArrow position="bottom" withinPortal>
15+
<Flex
16+
pos="absolute"
17+
bg="teal.7"
18+
w={22}
19+
h={22}
20+
top={-8}
21+
right={-8}
22+
bd="2px solid var(--mantine-color-dark-7)"
23+
align="center"
24+
justify="center"
25+
style={{ borderRadius: "50%", pointerEvents: "none" }}
26+
data-testid={testId}
27+
>
28+
<IconClock size={13} color="white" stroke={2.5} />
29+
</Flex>
30+
</Tooltip>
31+
);
32+
}
Lines changed: 85 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,103 @@
11
import UserSubmissions from "@/app/user/[userId]/submissions/_components/UserSubmissions/UserSubmissions.tsx";
2+
import { useUserSubmissionsQuery } from "@/lib/api/queries/user";
23
import { TestUtils, TestUtilTypes } from "@/lib/test";
34
import { screen, cleanup } from "@testing-library/react";
45
import { v4 as uuid } from "uuid";
56

6-
describe("UserSubmissions succeeded", () => {
7-
afterEach(() => {
8-
cleanup();
9-
});
7+
const baseReturn = {
8+
data: undefined,
9+
status: "pending" as const,
10+
page: 1,
11+
goBack: vi.fn(),
12+
goForward: vi.fn(),
13+
goTo: vi.fn(),
14+
isPlaceholderData: false,
15+
searchQuery: "",
16+
setSearchQuery: vi.fn(),
17+
pointFilter: false,
18+
togglePointFilter: vi.fn(),
19+
topics: [],
20+
setTopics: vi.fn(),
21+
clearTopics: vi.fn(),
22+
startDate: undefined,
23+
endDate: undefined,
24+
setStartDate: vi.fn(),
25+
setEndDate: vi.fn(),
26+
};
27+
28+
const successBase = {
29+
...baseReturn,
30+
status: "success" as const,
31+
data: {
32+
payload: { items: [], pages: 0, hasNextPage: false },
33+
},
34+
};
35+
36+
vi.mock("@/lib/api/queries/user", () => ({
37+
useUserSubmissionsQuery: vi.fn(),
38+
}));
39+
40+
const mockQuery = vi.mocked(useUserSubmissionsQuery);
41+
type QueryReturn = ReturnType<typeof useUserSubmissionsQuery>;
1042

43+
describe("UserSubmissions", () => {
1144
let renderProviderFn: TestUtilTypes.RenderWithAllProvidersFn | null = null;
45+
1246
beforeEach(() => {
1347
renderProviderFn = TestUtils.getRenderWithAllProvidersFn();
48+
mockQuery.mockReturnValue(baseReturn as unknown as QueryReturn);
1449
});
1550

16-
it("should render skeleton stack of submissions initially", () => {
17-
const MOCK_USER_ID = uuid();
18-
renderProviderFn?.(<UserSubmissions userId={MOCK_USER_ID} />);
51+
afterEach(cleanup);
52+
53+
it("should render skeleton when status is pending", () => {
54+
renderProviderFn?.(<UserSubmissions userId={uuid()} />);
1955
const element = screen.getByTestId(
2056
"user-profile-skeleton-submissions-stack",
2157
);
2258
expect(element).toBeInTheDocument();
2359
expect(element).toBeVisible();
2460
});
61+
62+
it("should not show clock icon when no date range is set", () => {
63+
mockQuery.mockReturnValue(successBase as unknown as QueryReturn);
64+
renderProviderFn?.(<UserSubmissions userId={uuid()} />);
65+
expect(
66+
screen.queryByTestId("date-range-clock-icon-mobile"),
67+
).not.toBeInTheDocument();
68+
});
69+
70+
it("should show clock icon when only startDate is set", () => {
71+
mockQuery.mockReturnValue({
72+
...successBase,
73+
startDate: "2024-01-01",
74+
} as unknown as QueryReturn);
75+
renderProviderFn?.(<UserSubmissions userId={uuid()} />);
76+
expect(
77+
screen.getAllByTestId("date-range-clock-icon-mobile").length,
78+
).toBeGreaterThan(0);
79+
});
80+
81+
it("should show clock icon when only endDate is set", () => {
82+
mockQuery.mockReturnValue({
83+
...successBase,
84+
endDate: "2024-12-31",
85+
} as unknown as QueryReturn);
86+
renderProviderFn?.(<UserSubmissions userId={uuid()} />);
87+
expect(
88+
screen.getAllByTestId("date-range-clock-icon-mobile").length,
89+
).toBeGreaterThan(0);
90+
});
91+
92+
it("should show clock icon when full date range is set", () => {
93+
mockQuery.mockReturnValue({
94+
...successBase,
95+
startDate: "2024-01-01",
96+
endDate: "2024-12-31",
97+
} as unknown as QueryReturn);
98+
renderProviderFn?.(<UserSubmissions userId={uuid()} />);
99+
expect(
100+
screen.getAllByTestId("date-range-clock-icon-mobile").length,
101+
).toBeGreaterThan(0);
102+
});
25103
});

js/src/app/user/[userId]/submissions/_components/UserSubmissions/UserSubmissions.tsx

Lines changed: 48 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import DateRangePopover from "@/app/user/[userId]/submissions/_components/DateRangePopover/DateRangePopover";
22
import TopicFilterPopover from "@/app/user/[userId]/submissions/_components/TopicFilters/TopicFilterPopover";
3+
import { DateRangeClockIcon } from "@/app/user/[userId]/submissions/_components/UserSubmissions/DateRangeClockIcon";
34
import UserSubmissionsSkeleton from "@/app/user/[userId]/submissions/_components/UserSubmissions/UserSubmissionsSkeleton";
45
import FilterDropdown from "@/components/ui/dropdown/FilterDropdown";
56
import FilterDropdownItem from "@/components/ui/dropdown/FilterDropdownItem";
@@ -24,6 +25,7 @@ import {
2425
Flex,
2526
} from "@mantine/core";
2627
import { useMediaQuery } from "@mantine/hooks";
28+
import d from "dayjs";
2729
import { useMemo } from "react";
2830
import { Link } from "react-router-dom";
2931

@@ -54,15 +56,10 @@ export default function UserSubmissions({ userId }: { userId: string }) {
5456
});
5557

5658
const selectedTopicsSet = useMemo(() => new Set(topics), [topics]);
57-
5859
const isMobile = useMediaQuery("(max-width: 768px)");
5960

6061
if (status === "pending") {
61-
return (
62-
<>
63-
<UserSubmissionsSkeleton />
64-
</>
65-
);
62+
return <UserSubmissionsSkeleton />;
6663
}
6764

6865
if (status === "error") {
@@ -73,6 +70,37 @@ export default function UserSubmissions({ userId }: { userId: string }) {
7370

7471
const pageData = data.payload;
7572

73+
const dateRangeLabel =
74+
(startDate || endDate) &&
75+
`Viewing submissions from ${startDate ? d(startDate).format("MMM D, YYYY") : "now"} to ${endDate ? d(endDate).format("MMM D, YYYY") : "now"}`;
76+
77+
const filterControls = (
78+
<FilterDropdown buttonName="Filters">
79+
<TopicFilterPopover
80+
value={topics}
81+
selectedTopicsSet={selectedTopicsSet}
82+
onChange={setTopics}
83+
onClear={clearTopics}
84+
/>
85+
<FilterDropdownItem
86+
value={pointFilter}
87+
toggle={togglePointFilter}
88+
switchMode
89+
name={
90+
<Flex gap="0.5rem" align="center">
91+
Points Received
92+
</Flex>
93+
}
94+
/>
95+
<DateRangePopover
96+
startDate={startDate}
97+
endDate={endDate}
98+
onStartDateChange={setStartDate}
99+
onEndDateChange={setEndDate}
100+
/>
101+
</FilterDropdown>
102+
);
103+
76104
return (
77105
<Box
78106
mt={10}
@@ -84,30 +112,10 @@ export default function UserSubmissions({ userId }: { userId: string }) {
84112
>
85113
{!isMobile && (
86114
<Box display="block" style={{ textAlign: "right" }}>
87-
<FilterDropdown buttonName="Filters">
88-
<TopicFilterPopover
89-
value={topics}
90-
selectedTopicsSet={selectedTopicsSet}
91-
onChange={setTopics}
92-
onClear={clearTopics}
93-
/>
94-
<FilterDropdownItem
95-
value={pointFilter}
96-
toggle={togglePointFilter}
97-
switchMode
98-
name={
99-
<Flex gap="0.5rem" align="center">
100-
Points Received
101-
</Flex>
102-
}
103-
/>
104-
<DateRangePopover
105-
startDate={startDate}
106-
endDate={endDate}
107-
onStartDateChange={setStartDate}
108-
onEndDateChange={setEndDate}
109-
/>
110-
</FilterDropdown>
115+
<Box pos="relative" display="inline-block">
116+
{filterControls}
117+
{dateRangeLabel && <DateRangeClockIcon label={dateRangeLabel} />}
118+
</Box>
111119
</Box>
112120
)}
113121
<Group
@@ -127,30 +135,10 @@ export default function UserSubmissions({ userId }: { userId: string }) {
127135
/>
128136
</Box>
129137
{isMobile && (
130-
<FilterDropdown buttonName="Filters">
131-
<TopicFilterPopover
132-
value={topics}
133-
selectedTopicsSet={selectedTopicsSet}
134-
onChange={setTopics}
135-
onClear={clearTopics}
136-
/>
137-
<FilterDropdownItem
138-
value={pointFilter}
139-
toggle={togglePointFilter}
140-
switchMode
141-
name={
142-
<Flex gap="0.5rem" align="center">
143-
Points Received
144-
</Flex>
145-
}
146-
/>
147-
<DateRangePopover
148-
startDate={startDate}
149-
endDate={endDate}
150-
onStartDateChange={setStartDate}
151-
onEndDateChange={setEndDate}
152-
/>
153-
</FilterDropdown>
138+
<Box pos="relative" style={{ flexShrink: 0 }}>
139+
{filterControls}
140+
{dateRangeLabel && <DateRangeClockIcon label={dateRangeLabel} />}
141+
</Box>
154142
)}
155143
</Group>
156144
<Box pos="relative">
@@ -178,28 +166,16 @@ export default function UserSubmissions({ userId }: { userId: string }) {
178166
</Card>
179167
: pageData.items.map((submission) => {
180168
const badgeDifficultyColor = (() => {
181-
if (submission.questionDifficulty === "Easy") {
182-
return undefined;
183-
}
184-
if (submission.questionDifficulty === "Medium") {
185-
return "yellow";
186-
}
187-
if (submission.questionDifficulty === "Hard") {
188-
return "red";
189-
}
169+
if (submission.questionDifficulty === "Easy") return undefined;
170+
if (submission.questionDifficulty === "Medium") return "yellow";
171+
if (submission.questionDifficulty === "Hard") return "red";
190172
return undefined;
191173
})();
192174
const badgeAcceptedColor = (() => {
193175
const acceptanceRate = submission.acceptanceRate * 100;
194-
if (acceptanceRate >= 75) {
195-
return undefined;
196-
}
197-
if (acceptanceRate >= 50) {
198-
return "yellow";
199-
}
200-
if (acceptanceRate >= 0) {
201-
return "red";
202-
}
176+
if (acceptanceRate >= 75) return undefined;
177+
if (acceptanceRate >= 50) return "yellow";
178+
if (acceptanceRate >= 0) return "red";
203179
return undefined;
204180
})();
205181
const LanguageIcon =

0 commit comments

Comments
 (0)