diff --git a/client/src/components/daily-coding-challenge/calendar-day.tsx b/client/src/components/daily-coding-challenge/calendar-day.tsx
index 91d5968a1b5..ef6038d6808 100644
--- a/client/src/components/daily-coding-challenge/calendar-day.tsx
+++ b/client/src/components/daily-coding-challenge/calendar-day.tsx
@@ -1,26 +1,50 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
+import { Spacer } from '@freecodecamp/ui';
import { Link } from '../helpers';
import GreenPass from '../../assets/icons/green-pass';
import GreenNotCompleted from '../../assets/icons/green-not-completed';
+import JavaScriptIcon from '../../assets/icons/javascript';
+import PythonIcon from '../../assets/icons/python';
import { formatDisplayDate } from './helpers';
interface CalendarDayProps {
dayNumber: number;
date?: string;
- isCompleted?: boolean;
+ challengeNumber?: number;
+ completedLanguages?: string[];
isAvailable?: boolean;
+ title?: string;
}
-// Todo: Change this to render checkmarks for JS and Python
+function Checkmark({ completed }: { completed: boolean }): JSX.Element {
+ return completed ? (
+
+
+
+ ) : (
+
+
+
+ );
+}
function DailyCodingChallengeCalendarDay({
dayNumber,
date,
- isCompleted = false,
- isAvailable = false
+ isAvailable = false,
+ title,
+ completedLanguages = [],
+ challengeNumber
}: CalendarDayProps): JSX.Element {
const { t } = useTranslation();
+
// dayNumber = 0 -> render nothing
if (dayNumber === 0) return
;
@@ -50,21 +74,41 @@ function DailyCodingChallengeCalendarDay({
{dayNumber}
- {isCompleted ? (
-
-
-
- ) : (
-
-
-
- )}
+ #{challengeNumber}
+
+
+
{title}
+
+ {completedLanguages.length === 2 ? (
+
+
+
+
+
+
+ ) : (
+
+ )}
+
);
}
diff --git a/client/src/components/daily-coding-challenge/calendar.css b/client/src/components/daily-coding-challenge/calendar.css
index e78dc3795da..e673c92f904 100644
--- a/client/src/components/daily-coding-challenge/calendar.css
+++ b/client/src/components/daily-coding-challenge/calendar.css
@@ -2,6 +2,9 @@
display: grid;
grid-template-columns: repeat(7, 1fr);
text-align: center;
+ margin: 0 auto;
+ max-width: 1500px;
+ padding: 0 20px;
}
.calendar-head {
@@ -18,18 +21,85 @@
display: grid;
grid-template-columns: repeat(7, 1fr); /* 7 columns for days of the week */
gap: 4px;
+ margin: 0 auto;
+ max-width: 1500px;
+ padding: 0 20px;
}
.calendar-day {
- display: flex;
- justify-content: center;
- align-items: center;
position: relative;
- padding: 10px;
- min-height: 100px;
+ padding: 10px 10px 20px;
+ min-height: 200px;
border: 1px solid var(--tertiary-color);
- text-align: center;
background-color: var(--primary-background);
+ text-decoration: none;
+}
+
+.calendar-day-number {
+ position: absolute;
+ top: 0;
+ left: 5px;
+}
+
+.dc-number {
+ font-style: italic;
+ color: var(--gray-45);
+ text-align: center;
+}
+
+.dc-info {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+}
+
+.dc-title {
+ width: 100%;
+ text-align: center;
+ align-self: center;
+ margin-top: 5px;
+ height: 50px;
+ margin-bottom: -5px;
+}
+
+.dc-languages {
+ padding: 0 15px;
+}
+
+.dc-language {
+ font-size: 0.8rem;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 10px;
+}
+
+.dc-language-icon {
+ fill: var(--primary-color);
+}
+
+.dc-language-icon svg {
+ width: 25px;
+ height: 25px;
+}
+
+.dc-small-checkmark {
+ position: relative;
+ /* top: -5px; */
+}
+
+.dc-small-checkmark svg {
+ width: 20px;
+ height: 20px;
+}
+
+.dc-big-checkmark {
+ margin: 0 auto;
+}
+
+.dc-big-checkmark svg {
+ width: 50px;
+ height: 50px;
}
.not-available:hover,
@@ -38,22 +108,24 @@
background-color: var(--primary-background);
}
-.not-available:hover .calendar-day-number,
-.not-available:active .calendar-day-number {
- color: var(--primary-color);
-}
-
.available:hover,
.available:active {
cursor: pointer;
background-color: var(--primary-color);
}
+.not-available:hover .calendar-day-number,
+.not-available:active .calendar-day-number {
+ color: var(--primary-color);
+}
+
.available:hover .calendar-day-number,
.available:active .calendar-day-number {
color: var(--primary-background);
}
+.available:hover .dc-language-icon svg path,
+.available:active .dc-language-icon svg path,
.available:hover .completed svg circle,
.available:active .completed svg circle {
fill: var(--primary-background);
@@ -72,27 +144,16 @@
stroke: var(--primary-color);
}
-.calendar-day-number {
- position: absolute;
- top: 0;
- left: 5px;
+.available:hover .dc-title,
+.available:active .dc-title,
+.available:hover .dc-language-name,
+.available:active .dc-language-name {
+ color: var(--primary-background);
}
-.calendar-day svg,
-.empty-cirle {
- width: calc(10px + 2vw);
- height: calc(10px + 2vw);
- max-width: 40px;
- max-height: 40px;
-}
-
-.empty-cirle {
- width: calc(10px + 2vw);
- height: calc(10px + 2vw);
- max-width: 40px;
- max-height: 40px;
- border-radius: 50%;
- border: 2px solid var(--primary-color);
+.available:hover .dc-number,
+.available:active .dc-number {
+ color: var(--quaternary-background);
}
@media (max-width: 500px) {
@@ -100,3 +161,75 @@
min-height: 75px;
}
}
+
+@media (max-width: 1345px) {
+ .calendar-day-number,
+ .dc-number,
+ .dc-title {
+ font-size: 0.8rem;
+ }
+
+ .dc-info hr {
+ margin: 10px 0;
+ }
+
+ .calendar-day {
+ min-height: 170px;
+ }
+
+ .dc-language {
+ justify-content: center;
+ }
+
+ .dc-language-name {
+ display: none;
+ }
+}
+
+@media (max-width: 1115px) {
+ .calendar-grid {
+ max-width: unset;
+ }
+
+ .calendar-day {
+ min-height: 125px;
+ padding: 10px;
+ }
+
+ .dc-title,
+ .dc-info hr {
+ display: none;
+ }
+
+ .dc-info {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 80%;
+ }
+
+ .dc-spacer {
+ display: none;
+ }
+}
+
+@media (max-width: 815px) {
+ .calendar-day {
+ min-height: 100px;
+ padding: 0;
+ }
+
+ .dc-number {
+ text-align: right;
+ padding-right: 5px;
+ }
+
+ .dc-languages {
+ padding: 0;
+ }
+
+ .dc-big-checkmark svg {
+ width: 40px;
+ height: 40px;
+ }
+}
diff --git a/client/src/components/daily-coding-challenge/calendar.tsx b/client/src/components/daily-coding-challenge/calendar.tsx
index 231013ef26a..41420235de8 100644
--- a/client/src/components/daily-coding-challenge/calendar.tsx
+++ b/client/src/components/daily-coding-challenge/calendar.tsx
@@ -1,12 +1,15 @@
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { useTranslation } from 'react-i18next';
-import { Button, Callout, Col, Spacer } from '@freecodecamp/ui';
+import { Button, Callout, Container, Col, Row, Spacer } from '@freecodecamp/ui';
import {
completedDailyCodingChallengesSelector,
isSignedInSelector
} from '../../redux/selectors';
-import { CompletedDailyCodingChallenge } from '../../redux/prop-types';
+import {
+ CompletedDailyCodingChallenge,
+ DailyCodingChallengeLanguages
+} from '../../redux/prop-types';
import { Loader } from '../helpers';
import envData from '../../../config/env.json';
import Login from '../Header/components/login';
@@ -40,9 +43,9 @@ interface AllDailyChallengeFromDb {
interface DailyChallengeMap {
id: string;
date: string;
- isCompleted: boolean;
challengeNumber: number;
title: string;
+ completedLanguages: DailyCodingChallengeLanguages[];
}
type DailyChallengesMap = Map;
@@ -85,16 +88,20 @@ const getMonthInfo = (
});
const challengeData = dailyChallengesMap.get(formattedDate);
- const isCompleted = challengeData?.isCompleted || false;
+ const completedLanguages = challengeData?.completedLanguages || [];
+ const title = challengeData?.title || '';
const isAvailable = challengeData !== undefined;
+ const challengeNumber = challengeData?.challengeNumber;
days.push(
);
}
@@ -118,10 +125,6 @@ function DailyCodingChallengeCalendar({
const todayUsCentral = getTodayUsCentral();
- const completedDailyCodingChallengeIds = completedDailyCodingChallenges.map(
- c => c.id
- );
-
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(false);
const [monthInfo, setMonthInfo] = useState(null);
@@ -145,7 +148,9 @@ function DailyCodingChallengeCalendar({
newDailyChallengesMap.set(date, {
...c,
date,
- isCompleted: completedDailyCodingChallengeIds.includes(c.id)
+ completedLanguages:
+ completedDailyCodingChallenges.find(ch => ch.id === c.id)
+ ?.languages ?? []
});
});
@@ -231,18 +236,22 @@ function DailyCodingChallengeCalendar({
return (
<>
-
-
- {t('daily-coding-challenges.release-note')}
-
+
+
+
+
+ {t('daily-coding-challenges.release-note')}
+
-
-
+
+
+
+
diff --git a/client/src/pages/learn/daily-coding-challenge/archive.tsx b/client/src/pages/learn/daily-coding-challenge/archive.tsx
index 3c98fa0995c..a4e15e34803 100644
--- a/client/src/pages/learn/daily-coding-challenge/archive.tsx
+++ b/client/src/pages/learn/daily-coding-challenge/archive.tsx
@@ -9,25 +9,26 @@ function Archive(): JSX.Element {
const { t } = useTranslation();
return (
-
-
-
-
-
- {t('daily-coding-challenges.title')}
-
-
-
-
-
-
-
-
-
-
-
-
-
+ <>
+
+
+ {t('daily-coding-challenges.title')}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
);
}
diff --git a/client/src/redux/prop-types.ts b/client/src/redux/prop-types.ts
index 78f6af19aa3..b895d084fab 100644
--- a/client/src/redux/prop-types.ts
+++ b/client/src/redux/prop-types.ts
@@ -331,7 +331,7 @@ export type DailyCodingChallengeLanguages = 'javascript' | 'python';
export interface CompletedDailyCodingChallenge {
id: string;
completedDate: number;
- completedLanguages: DailyCodingChallengeLanguages[];
+ languages: DailyCodingChallengeLanguages[];
}
type Quiz = {
diff --git a/e2e/daily-coding-challenge.spec.ts b/e2e/daily-coding-challenge.spec.ts
index 1a16eb8203c..b0586353a3c 100644
--- a/e2e/daily-coding-challenge.spec.ts
+++ b/e2e/daily-coding-challenge.spec.ts
@@ -251,6 +251,6 @@ test.describe('Daily Coding Challenge Archive', () => {
await expect(page.getByTestId('calendar-day-completed')).toHaveCount(1);
- await expect(page.getByTestId('calendar-day-not-completed')).toHaveCount(1);
+ await expect(page.getByTestId('calendar-day-not-completed')).toHaveCount(3);
});
});