Skip to content

Commit fbfcdff

Browse files
authored
Merge pull request #623 from mapswipe/dev
Dev
2 parents c80cc6e + 45ba932 commit fbfcdff

File tree

31 files changed

+581
-406
lines changed

31 files changed

+581
-406
lines changed

.github/workflows/actions.yml

+7
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ jobs:
2727
black --check mapswipe_workers ../django
2828
flake8 --count --config setup.cfg mapswipe_workers/ ../django/
2929
isort --check --settings-file setup.cfg mapswipe_workers/ ../django/
30+
- name: Assert check
31+
run: |
32+
cmp --silent ./postgres/initdb.sql ./mapswipe_workers/tests/integration/set_up_db.sql || {
33+
echo 'The set_up_db.sql is not same as initdb.sql. Please sync this files and push';
34+
diff ./postgres/initdb.sql ./mapswipe_workers/tests/integration/set_up_db.sql;
35+
exit 1;
36+
}
3037
- name: Setup Postgres Database Container
3138
env:
3239
POSTGRES_PASSWORD: postgres

community-dashboard/app/components/DateRangeInput/index.tsx

+37-20
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ function DateRangeInput<N extends NameType>(props: Props<N>) {
131131
endDate: undefined,
132132
});
133133
const [calendarMonthSelectionPopupClassName] = React.useState(randomString(16));
134+
const [rangeInputClassName] = React.useState(randomString(16));
134135
const createdContainerRef = React.useRef<HTMLDivElement>(null);
135136
const popupRef = React.useRef<HTMLDivElement>(null);
136137

@@ -167,6 +168,15 @@ function DateRangeInput<N extends NameType>(props: Props<N>) {
167168
[hideCalendar, calendarMonthSelectionPopupClassName],
168169
);
169170

171+
React.useEffect(() => {
172+
if (showCalendar && window.innerWidth <= 528) {
173+
const el = document.getElementsByClassName(
174+
rangeInputClassName,
175+
)?.[0];
176+
el?.scrollIntoView(true);
177+
}
178+
}, [showCalendar, rangeInputClassName]);
179+
170180
useBlurEffect(
171181
showCalendar,
172182
handlePopupBlur,
@@ -311,7 +321,7 @@ function DateRangeInput<N extends NameType>(props: Props<N>) {
311321
</>
312322
)}
313323
actionsContainerClassName={actionsContainerClassName}
314-
className={className}
324+
className={_cs(rangeInputClassName, className)}
315325
disabled={disabled}
316326
error={error}
317327
errorContainerClassName={errorContainerClassName}
@@ -325,7 +335,13 @@ function DateRangeInput<N extends NameType>(props: Props<N>) {
325335
labelContainerClassName={labelContainerClassName}
326336
readOnly={readOnly}
327337
input={(
328-
<>
338+
<div
339+
className={styles.inputWrapper}
340+
onClick={toggleShowCalendar}
341+
onKeyPress={toggleShowCalendar}
342+
role="button"
343+
tabIndex={0}
344+
>
329345
<RawInput<string>
330346
name="startDate"
331347
className={_cs(
@@ -366,7 +382,7 @@ function DateRangeInput<N extends NameType>(props: Props<N>) {
366382
onFocus={setShowCalendarTrue}
367383
type="date"
368384
/>
369-
</>
385+
</div>
370386
)}
371387
/>
372388
{!readOnly && showCalendar && (
@@ -389,23 +405,24 @@ function DateRangeInput<N extends NameType>(props: Props<N>) {
389405
</RawButton>
390406
))}
391407
</div>
392-
393-
<Calendar
394-
onDateClick={handleCalendarDateClick}
395-
className={styles.calendar}
396-
monthSelectionPopupClassName={calendarMonthSelectionPopupClassName}
397-
dateRenderer={DateRenderer}
398-
rendererParams={dateRendererParams}
399-
initialDate={firstInitialDate}
400-
/>
401-
<Calendar
402-
onDateClick={handleCalendarDateClick}
403-
className={styles.calendar}
404-
monthSelectionPopupClassName={calendarMonthSelectionPopupClassName}
405-
dateRenderer={DateRenderer}
406-
rendererParams={dateRendererParams}
407-
initialDate={secondInitialDate}
408-
/>
408+
<div className={styles.calendars}>
409+
<Calendar
410+
onDateClick={handleCalendarDateClick}
411+
className={styles.calendar}
412+
monthSelectionPopupClassName={calendarMonthSelectionPopupClassName}
413+
dateRenderer={DateRenderer}
414+
rendererParams={dateRendererParams}
415+
initialDate={firstInitialDate}
416+
/>
417+
<Calendar
418+
onDateClick={handleCalendarDateClick}
419+
className={styles.calendar}
420+
monthSelectionPopupClassName={calendarMonthSelectionPopupClassName}
421+
dateRenderer={DateRenderer}
422+
rendererParams={dateRendererParams}
423+
initialDate={secondInitialDate}
424+
/>
425+
</div>
409426
</Popup>
410427
)}
411428
</>

community-dashboard/app/components/DateRangeInput/styles.css

+54-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
.input-container {
22
display: flex;
33
flex-direction: row;
4+
cursor: pointer;
5+
6+
.input-wrapper {
7+
display: flex;
8+
align-items: center;
9+
}
410

511
.input {
612
--color: var(--color-text);
13+
cursor: pointer;
714
color: var(--color);
815

916
&.empty {
@@ -41,10 +48,14 @@
4148
max-width: unset!important;
4249
max-height: unset!important;
4350

44-
.calendar {
45-
--padding: var(--spacing-medium);
46-
width: calc(var(--width-calendar-date) * 7 + 2 * var(--padding));
47-
height: 100%;
51+
.calendars {
52+
display: flex;
53+
54+
.calendar {
55+
--padding: var(--spacing-medium);
56+
width: calc(var(--width-calendar-date) * 7 + 2 * var(--padding));
57+
height: 100%;
58+
}
4859
}
4960

5061
.predefined-options {
@@ -64,6 +75,45 @@
6475
}
6576
}
6677
}
78+
79+
@media screen and (max-width: 50rem) {
80+
height: auto;
81+
82+
.popup-content {
83+
flex-wrap: wrap;
84+
85+
.calendars {
86+
order: 1;
87+
88+
.calendar {
89+
flex-grow: 1;
90+
width: auto;
91+
height: unset;
92+
}
93+
}
94+
95+
.predefined-options {
96+
flex-direction: row;
97+
flex-wrap: wrap;
98+
order: 2;
99+
text-align: initial;
100+
101+
.option {
102+
justify-content: unset;
103+
width: auto;
104+
}
105+
}
106+
107+
}
108+
}
109+
110+
@media screen and (max-width: 33rem) {
111+
.popup-content {
112+
.calendars {
113+
flex-wrap: wrap;
114+
}
115+
}
116+
}
67117
}
68118

69119
.calendar-date {

community-dashboard/app/components/Page/index.tsx

+37
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import groupSvg from '#resources/icons/group.svg';
1818
import swipeSvg from '#resources/icons/swipe.svg';
1919
import timeSvg from '#resources/icons/time.svg';
2020

21+
import { formatTimeDuration } from '#utils/temporal';
2122
import styles from './styles.css';
2223

2324
interface InfoStatCardProps {
@@ -28,6 +29,7 @@ interface InfoStatCardProps {
2829
secondaryValue?: number;
2930
secondaryValueLabel?: React.ReactNode;
3031
secondaryValueDescription?: React.ReactNode;
32+
variant?: 'time' | 'number';
3133
}
3234

3335
function InfoStatCard(props: InfoStatCardProps) {
@@ -39,8 +41,42 @@ function InfoStatCard(props: InfoStatCardProps) {
3941
secondaryValue,
4042
secondaryValueLabel,
4143
secondaryValueDescription,
44+
variant,
4245
} = props;
4346

47+
if (variant === 'time' && isDefined(value)) {
48+
return (
49+
<InformationCard
50+
icon={(
51+
<img
52+
src={iconUrl}
53+
alt={iconAlt}
54+
className={styles.image}
55+
/>
56+
)}
57+
value={(
58+
<TextOutput
59+
value={formatTimeDuration(value, ' ', true)}
60+
/>
61+
)}
62+
label={label}
63+
description={isDefined(secondaryValue) && secondaryValue > 0 && (
64+
<TextOutput
65+
label={secondaryValueLabel}
66+
hideLabelColon
67+
valueType="text"
68+
value={(
69+
<TextOutput
70+
value={formatTimeDuration(secondaryValue, ' ', true)}
71+
/>
72+
)}
73+
description={secondaryValueDescription}
74+
/>
75+
)}
76+
/>
77+
);
78+
}
79+
4480
return (
4581
<InformationCard
4682
icon={(
@@ -174,6 +210,7 @@ function Page(props: Props) {
174210
// eslint-disable-next-line react/destructuring-assignment
175211
secondaryValue={props.totalTimeSpentLastMonth}
176212
secondaryValueDescription="in the last 30 days"
213+
variant="time"
177214
/>
178215
)}
179216
{/* eslint-disable-next-line react/destructuring-assignment */}

community-dashboard/app/views/StatsBoard/index.tsx

+7-5
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ interface Props {
175175
className?: string;
176176
heading?: string;
177177
contributionTimeStats: ActualContributorTimeStatType[] | null | undefined;
178-
contributionSwipeStats: ContributorSwipeStatType[] | null | undefined;
178+
contributionSwipeStats?: ContributorSwipeStatType[] | null | undefined;
179179
areaSwipedByProjectType: ProjectTypeAreaStatsType[] | null | undefined;
180180
organizationTypeStats: OrganizationSwipeStatsType[] | null | undefined;
181181
swipeByProjectType: ProjectTypeSwipeStatsType[] | null | undefined;
@@ -364,7 +364,7 @@ function StatsBoard(props: Props) {
364364
...item,
365365
projectType: item.projectType ?? '-1',
366366
}))
367-
.sort((a, b) => compareNumber(b.totalSwipes, a.totalSwipes)) ?? []
367+
.sort((a, b) => compareNumber(a.totalSwipes, b.totalSwipes)) ?? []
368368
),
369369
[swipeByProjectType],
370370
);
@@ -382,7 +382,7 @@ function StatsBoard(props: Props) {
382382
organizationName: item.organizationName ?? 'Unknown',
383383
}))
384384
.filter((project) => isDefined(project.organizationName))
385-
.sort((a, b) => compareNumber(b.totalSwipes, a.totalSwipes)) ?? [];
385+
.sort((a, b) => compareNumber(a.totalSwipes, b.totalSwipes)) ?? [];
386386

387387
if (sortedTotalSwipeByOrganization.length <= 5) {
388388
return sortedTotalSwipeByOrganization;
@@ -678,11 +678,11 @@ function StatsBoard(props: Props) {
678678
normal
679679
/>
680680
)}
681-
label="Total Swipes"
681+
label="Swipes"
682682
variant="stat"
683683
/>
684684
<InformationCard
685-
label="Total Time Spent Contributing"
685+
label="Time Spent Contributing"
686686
value={(isDefined(totalContribution) && totalContribution > 0) ? (
687687
<TextOutput
688688
className={styles.numberOutput}
@@ -722,6 +722,7 @@ function StatsBoard(props: Props) {
722722
cy="50%"
723723
outerRadius="90%"
724724
innerRadius="50%"
725+
startAngle={-270}
725726
>
726727
{sortedProjectSwipeType.map((item) => (
727728
<Cell
@@ -765,6 +766,7 @@ function StatsBoard(props: Props) {
765766
cy="50%"
766767
outerRadius="90%"
767768
innerRadius="50%"
769+
startAngle={-270}
768770
>
769771
{totalSwipesByOrganizationStats.map((item) => (
770772
<Cell

community-dashboard/app/views/UserGroupDashboard/index.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ function UserGroupDashboard(props: Props) {
194194
const objUrl = URL.createObjectURL(blob);
195195
const link = document.createElement('a');
196196
link.href = objUrl;
197-
link.download = `${userGroupStats.userGroup.name}.csv`;
197+
link.download = `${userGroupStats?.userGroup?.name ?? 'users'}.csv`;
198198
document.body.appendChild(link);
199199
link.dispatchEvent(
200200
new MouseEvent('click', {
@@ -206,7 +206,6 @@ function UserGroupDashboard(props: Props) {
206206
document.body.removeChild(link);
207207
window.URL.revokeObjectURL(objUrl);
208208
},
209-
skip: !userGroupId,
210209
},
211210
);
212211

@@ -281,6 +280,7 @@ function UserGroupDashboard(props: Props) {
281280
<Button
282281
disabled={userGroupStatsDownloadLoading}
283282
onClick={getUserGroupStatsDownload}
283+
name="export"
284284
>
285285
{ userGroupStatsDownloadLoading ? 'Exporting' : 'Export' }
286286
</Button>

0 commit comments

Comments
 (0)