Skip to content

Commit a4f355e

Browse files
committed
Redesign streak progress
1 parent 4697719 commit a4f355e

File tree

16 files changed

+487
-217
lines changed

16 files changed

+487
-217
lines changed

locales/en/reading-goal.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@
9191
"remaining": "Remaining for today",
9292
"remaining-base": "Remaining",
9393
"remaining-days": {
94-
"one": "{{days}} day remaining",
95-
"other": "{{days}} days remaining"
94+
"one": "<span>{{days}}</span> day remaining",
95+
"other": "<span>{{days}}</span> days remaining"
9696
},
9797
"set-a-new-goal": "Set a new Goal",
9898
"set-reading-goal-success": "Your reading goal has been set successfully.",
@@ -111,10 +111,10 @@
111111
},
112112
"todays-goal": "Today's Goal",
113113
"view-progress": "View Progress",
114-
"week-progress": "This week's progress",
114+
"week-progress": "This Week's Progress",
115115
"x-days": {
116-
"one": "{{days}} day",
117-
"other": "{{days}} days"
116+
"one": "<span>{{days}}</span> Day streak",
117+
"other": "<span>{{days}}</span> Days streak"
118118
},
119119
"x-days-streak": "<p>{{days}}</p> <span>day streak</span>",
120120
"x-hours": {

public/icons/arrow-left.svg

Lines changed: 10 additions & 0 deletions
Loading

src/components/HomePage/QuranGrowthJourneySection/CollapsibleSection/QuranReadingGoals/CurrentWeekProgress.tsx

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,25 @@ const CurrentWeekProgress: React.FC<Props> = ({ weekData, goal, fixedWidth = tru
2525
const hasRead = readingDay?.hasRead;
2626

2727
// if the user has a goal, we want to show a checked circle if the user has completed his goal for the day
28-
// otherwise, we want to show a filled circle if the user has read at all for the day
28+
// otherwise, we want to show a checked circle if the user has read at all for the day
2929
const isGoalDone = goal ? convertFractionToPercent(readingDay?.progress || 0) >= 100 : hasRead;
3030

3131
if (isGoalDone) return DayState.Checked;
32-
if (hasRead) return DayState.Filled;
3332

34-
return day.current ? DayState.Stroked : DayState.None;
33+
// Check if the day is in the future
34+
const today = new Date();
35+
today.setHours(0, 0, 0, 0);
36+
const dayDate = new Date(day.date);
37+
dayDate.setHours(0, 0, 0, 0);
38+
39+
if (dayDate > today) return DayState.Future;
40+
41+
return DayState.None;
3542
};
3643

3744
return (
38-
<div>
39-
<p className={styles.weekProgressLabel}>{t('reading-goal:week-progress')}</p>
45+
<div className={styles.currentWeekProgress}>
46+
<p className={styles.weekProgressLabel}>{t('reading-goal:week-progress')}:</p>
4047
<div
4148
className={classNames(styles.week, {
4249
[styles.fixedWidth]: fixedWidth,
@@ -45,21 +52,31 @@ const CurrentWeekProgress: React.FC<Props> = ({ weekData, goal, fixedWidth = tru
4552
{days.map((day) => {
4653
const dayState = getDayState(day);
4754

55+
const today = new Date();
56+
today.setHours(0, 0, 0, 0);
57+
const dayDate = new Date(day.date);
58+
dayDate.setHours(0, 0, 0, 0);
59+
const isToday = dayDate.getTime() === today.getTime();
60+
4861
return (
4962
<div key={day.info.localizedNumber} className={styles.day}>
63+
<div className={styles.circleContainer}>
64+
<DayCircle state={dayState} />
65+
</div>
5066
<HoverablePopover
5167
content={dateToReadableFormat(day.date, lang)}
52-
contentSide={ContentSide.TOP}
68+
contentSide={ContentSide.BOTTOM}
5369
>
54-
<span className={styles.fullName}>{day.info.title}</span>
55-
<span className={styles.shortName}>{day.info.localizedNumber}</span>
70+
<span
71+
className={classNames(styles.shortName, {
72+
[styles.textBold]: isToday,
73+
})}
74+
>
75+
{dayState === DayState.Future || isToday
76+
? day.info.localizedNumber
77+
: day.info.shortName}
78+
</span>
5679
</HoverablePopover>
57-
58-
<div className={styles.circleContainer}>
59-
<DayCircle state={dayState} />
60-
61-
<div className={styles.dayDivider} />
62-
</div>
6380
</div>
6481
);
6582
})}

src/components/HomePage/QuranGrowthJourneySection/CollapsibleSection/QuranReadingGoals/DayCircle/DayCircle.module.scss

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
width: var(--spacing-large);
33
height: var(--spacing-large);
44
border-radius: var(--border-radius-circle);
5-
border: 2px solid var(--color-success-medium);
6-
background-color: var(--day-circle-color);
5+
border: 2px solid var(--color-blue-buttons-and-icons);
6+
background-color: var(--color-background-default);
77
display: flex;
88
justify-content: center;
99
align-items: center;
@@ -12,7 +12,7 @@
1212
inset-block-start: 50%;
1313
transform: translate(-50%, -50%);
1414

15-
[dir="rtl"] & {
15+
[dir='rtl'] & {
1616
transform: translate(50%, -50%);
1717
}
1818

@@ -23,10 +23,11 @@
2323
}
2424
}
2525

26-
.filled {
27-
background-color: var(--color-success-medium) !important;
26+
.checked {
27+
background-color: var(--color-blue-buttons-and-icons);
2828
}
2929

30-
.stroked {
31-
border-style: dashed;
30+
.future {
31+
border-color: var(--color-daily-progress);
32+
background-color: var(--color-daily-progress);
3233
}

src/components/HomePage/QuranGrowthJourneySection/CollapsibleSection/QuranReadingGoals/DayCircle/index.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ import CheckIcon from '@/icons/check.svg';
66

77
export enum DayState {
88
None = 'none',
9-
Stroked = 'stroked',
10-
Filled = 'filled',
119
Checked = 'checked',
10+
Future = 'future',
1211
}
1312

1413
interface DayCircleProps {
@@ -19,8 +18,8 @@ const DayCircle: React.FC<DayCircleProps> = ({ state }) => {
1918
return (
2019
<div
2120
className={classNames(styles.dayCircle, {
22-
[styles.filled]: state === DayState.Filled || state === DayState.Checked,
23-
[styles.stroked]: state === DayState.Stroked,
21+
[styles.checked]: state === DayState.Checked,
22+
[styles.future]: state === DayState.Future,
2423
})}
2524
>
2625
{state === DayState.Checked ? <CheckIcon /> : null}

src/components/HomePage/QuranGrowthJourneySection/CollapsibleSection/QuranReadingGoals/ReadingStreak.module.scss

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
@use "src/styles/theme";
2-
@use "src/styles/breakpoints";
1+
@use 'src/styles/theme';
2+
@use 'src/styles/breakpoints';
33

44
.container {
55
display: flex;
@@ -21,8 +21,14 @@
2121
color: var(--color-text-default-new);
2222
}
2323

24+
.currentWeekProgress {
25+
display: flex;
26+
flex-direction: column;
27+
gap: var(--spacing-medium);
28+
}
29+
2430
.weekProgressLabel {
25-
font-weight: var(--font-weight-medium);
31+
font-weight: var(--font-weight-bold);
2632
}
2733

2834
.week {
@@ -48,22 +54,15 @@
4854
gap: var(--spacing-large);
4955
}
5056

51-
.fullName {
52-
display: none;
53-
54-
@include breakpoints.tablet {
55-
display: block;
56-
}
57-
}
58-
5957
.shortName {
60-
display: none;
58+
color: var(--color-text-default-new);
59+
font-size: var(--font-size-normal);
60+
font-weight: var(--font-weight-medium);
61+
display: block;
62+
}
6163

62-
@include breakpoints.smallerThanTablet {
63-
font-size: var(--font-size-normal);
64-
font-weight: var(--font-weight-medium);
65-
display: block;
66-
}
64+
.textBold {
65+
font-weight: var(--font-weight-bold);
6766
}
6867

6968
.circleContainer {
@@ -72,12 +71,6 @@
7271
position: relative;
7372
}
7473

75-
.dayDivider {
76-
width: 100%;
77-
height: 2px;
78-
background-color: var(--color-success-medium);
79-
}
80-
8174
.goalContainer {
8275
margin-block-start: var(--spacing-mega);
8376
}

src/components/ReadingGoal/DeleteReadingGoalModal/index.tsx

Lines changed: 38 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ import { makeStreakUrl } from '@/utils/auth/apiPaths';
1616
import { logButtonClick } from '@/utils/eventLogger';
1717

1818
type DeleteReadingGoalButtonProps = {
19-
isDisabled?: boolean;
19+
isOpen: boolean;
20+
onModalChange: (visible: boolean) => void;
2021
};
2122

22-
const DeleteReadingGoalModal = ({ isDisabled }: DeleteReadingGoalButtonProps) => {
23+
const DeleteReadingGoalModal = ({ isOpen, onModalChange }: DeleteReadingGoalButtonProps) => {
2324
const { t } = useTranslation('reading-progress');
24-
const [isModalVisible, setIsModalVisible] = useState(false);
2525
const [confirmationText, setConfirmationText] = useState('');
2626
const { mutate } = useSWRConfig();
2727
const toast = useToast();
@@ -33,7 +33,7 @@ const DeleteReadingGoalModal = ({ isDisabled }: DeleteReadingGoalButtonProps) =>
3333

3434
const closeModal = () => {
3535
setConfirmationText('');
36-
setIsModalVisible(false);
36+
onModalChange(false);
3737
};
3838

3939
const onDeleteConfirmed = async () => {
@@ -45,61 +45,46 @@ const DeleteReadingGoalModal = ({ isDisabled }: DeleteReadingGoalButtonProps) =>
4545
closeModal();
4646
};
4747

48-
const onDeleteReadingGoalClicked = () => {
49-
logButtonClick('reading_goal_delete');
50-
setIsModalVisible(true);
51-
};
52-
5348
const CONFIRMATION_TEXT = t('delete-goal.confirmation.confirmation-text');
5449
const canDeleteGoal = confirmationText.toLowerCase() === CONFIRMATION_TEXT.toLowerCase();
5550

5651
return (
57-
<>
58-
<Button
59-
type={ButtonType.Error}
60-
variant={ButtonVariant.Ghost}
61-
onClick={onDeleteReadingGoalClicked}
62-
isDisabled={isDisabled}
63-
>
64-
{t('delete-goal.action')}
65-
</Button>
66-
<Modal isOpen={isModalVisible} onClickOutside={closeModal}>
67-
<Modal.Body>
68-
<Modal.Header>
69-
<Modal.Title>{t('delete-goal.confirmation.title')}</Modal.Title>
70-
<Modal.Subtitle>{t('delete-goal.confirmation.subtitle')}</Modal.Subtitle>
52+
<Modal isOpen={isOpen} onClickOutside={closeModal}>
53+
<Modal.Body>
54+
<Modal.Header>
55+
<Modal.Title>{t('delete-goal.confirmation.title')}</Modal.Title>
56+
<Modal.Subtitle>{t('delete-goal.confirmation.subtitle')}</Modal.Subtitle>
7157

72-
<p className={styles.instructionText}>
73-
<Trans
74-
i18nKey="reading-progress:delete-goal.confirmation.instruction-text"
75-
values={{ text: CONFIRMATION_TEXT }}
76-
components={{
77-
strong: <strong className={styles.confirmationText} />,
78-
}}
79-
/>
80-
</p>
81-
<Input
82-
id="delete-goal-confirmation"
83-
value={confirmationText}
84-
onChange={setConfirmationText}
85-
fixedWidth={false}
86-
containerClassName={styles.inputContainer}
58+
<p className={styles.instructionText}>
59+
<Trans
60+
i18nKey="reading-progress:delete-goal.confirmation.instruction-text"
61+
values={{ text: CONFIRMATION_TEXT }}
62+
components={{
63+
strong: <strong className={styles.confirmationText} />,
64+
}}
8765
/>
88-
</Modal.Header>
89-
<Modal.Footer>
90-
<Button
91-
type={ButtonType.Error}
92-
variant={ButtonVariant.Outlined}
93-
className={styles.deleteButton}
94-
onClick={onDeleteConfirmed}
95-
isDisabled={!canDeleteGoal}
96-
>
97-
{t('delete-goal.confirmation.action-text')}
98-
</Button>
99-
</Modal.Footer>
100-
</Modal.Body>
101-
</Modal>
102-
</>
66+
</p>
67+
<Input
68+
id="delete-goal-confirmation"
69+
value={confirmationText}
70+
onChange={setConfirmationText}
71+
fixedWidth={false}
72+
containerClassName={styles.inputContainer}
73+
/>
74+
</Modal.Header>
75+
<Modal.Footer>
76+
<Button
77+
type={ButtonType.Error}
78+
variant={ButtonVariant.Outlined}
79+
className={styles.deleteButton}
80+
onClick={onDeleteConfirmed}
81+
isDisabled={!canDeleteGoal}
82+
>
83+
{t('delete-goal.confirmation.action-text')}
84+
</Button>
85+
</Modal.Footer>
86+
</Modal.Body>
87+
</Modal>
10388
);
10489
};
10590

src/components/ReadingGoal/UpdateReadingGoalModal/UpdateReadingGoalModal.module.scss

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@use 'src/styles/breakpoints';
2+
13
.inputs {
24
width: 100%;
35
}
@@ -45,3 +47,23 @@
4547
align-items: center;
4648
gap: var(--spacing-xsmall);
4749
}
50+
51+
.footerCtaContainer {
52+
width: 100%;
53+
display: flex;
54+
flex-direction: column;
55+
gap: var(--spacing-micro);
56+
}
57+
58+
.editGoalButton {
59+
background-color: var(--color-streaks-dark);
60+
border: none;
61+
border-radius: calc(var(--border-radius-default) * 3);
62+
63+
@include breakpoints.tablet {
64+
background-color: initial;
65+
border: initial;
66+
border-radius: initial;
67+
color: var(--color-streaks-dark);
68+
}
69+
}

0 commit comments

Comments
 (0)