diff --git a/package.json b/package.json index 704922c45d..cc9e84de47 100644 --- a/package.json +++ b/package.json @@ -111,6 +111,7 @@ "lodash.isequal": "^4.5.0", "lodash.isobject": "^3.0.2", "lodash.kebabcase": "^4.1.1", + "lodash.mapvalues": "^4.6.0", "lodash.merge": "^4.6.2", "lodash.omit": "^4.5.0", "lodash.pick": "^4.4.0", @@ -225,6 +226,7 @@ "@types/lodash.isequal": "^4.5.7", "@types/lodash.isobject": "^3.0.7", "@types/lodash.kebabcase": "^4.1.7", + "@types/lodash.mapvalues": "^4.6.9", "@types/lodash.snakecase": "^4.1.7", "@types/lodash.upperfirst": "^4.3.7", "@types/luxon": "^3.3.0", diff --git a/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx b/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx index 85d9c603d7..97ad87b4e9 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/Calendar.tsx @@ -1,8 +1,11 @@ import styled from '@emotion/styled'; -import { startOfMonth } from 'date-fns'; +import { format, getYear, startOfMonth } from 'date-fns'; +import mapValues from 'lodash.mapvalues'; import { CalendarMonthCard } from '@/activities/calendar/components/CalendarMonthCard'; import { sortCalendarEventsDesc } from '@/activities/calendar/utils/sortCalendarEvents'; +import { H3Title } from '@/ui/display/typography/components/H3Title'; +import { Section } from '@/ui/layout/section/components/Section'; import { mockedCalendarEvents } from '~/testing/mock-data/calendar'; import { groupArrayItemsBy } from '~/utils/array/groupArrayItemsBy'; import { sortDesc } from '~/utils/sort'; @@ -16,6 +19,10 @@ const StyledContainer = styled.div` width: 100%; `; +const StyledYear = styled.span` + color: ${({ theme }) => theme.font.color.light}; +`; + export const Calendar = () => { const sortedCalendarEvents = [...mockedCalendarEvents].sort( sortCalendarEventsDesc, @@ -27,18 +34,32 @@ export const Calendar = () => { const sortedMonthTimes = Object.keys(calendarEventsByMonthTime) .map(Number) .sort(sortDesc); + const monthTimesByYear = groupArrayItemsBy(sortedMonthTimes, getYear); + const lastMonthTimeByYear = mapValues(monthTimesByYear, (monthTimes = []) => + Math.max(...monthTimes), + ); return ( {sortedMonthTimes.map((monthTime) => { const monthCalendarEvents = calendarEventsByMonthTime[monthTime]; + const year = getYear(monthTime); + const isLastMonthOfYear = lastMonthTimeByYear[year] === monthTime; + const monthLabel = format(monthTime, 'MMMM'); return ( !!monthCalendarEvents?.length && ( - +
+ + {monthLabel} + {isLastMonthOfYear && {year}} + + } + /> + +
) ); })} diff --git a/packages/twenty-front/src/modules/ui/display/typography/components/H3Title.tsx b/packages/twenty-front/src/modules/ui/display/typography/components/H3Title.tsx new file mode 100644 index 0000000000..4e8f8dcaae --- /dev/null +++ b/packages/twenty-front/src/modules/ui/display/typography/components/H3Title.tsx @@ -0,0 +1,19 @@ +import { ReactNode } from 'react'; +import styled from '@emotion/styled'; + +type H3TitleProps = { + title: ReactNode; + className?: string; +}; + +const StyledH3Title = styled.h3` + color: ${({ theme }) => theme.font.color.primary}; + font-size: ${({ theme }) => theme.font.size.lg}; + font-weight: ${({ theme }) => theme.font.weight.semiBold}; + margin: 0; + margin-bottom: ${({ theme }) => theme.spacing(4)}; +`; + +export const H3Title = ({ title, className }: H3TitleProps) => { + return {title}; +}; diff --git a/packages/twenty-front/src/modules/ui/display/typography/components/__stories__/H3Title.stories.tsx b/packages/twenty-front/src/modules/ui/display/typography/components/__stories__/H3Title.stories.tsx new file mode 100644 index 0000000000..7ea720df9e --- /dev/null +++ b/packages/twenty-front/src/modules/ui/display/typography/components/__stories__/H3Title.stories.tsx @@ -0,0 +1,22 @@ +import { Meta, StoryObj } from '@storybook/react'; + +import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator'; + +import { H3Title } from '../H3Title'; + +const meta: Meta = { + title: 'UI/Display/Typography/Title/H3Title', + component: H3Title, + decorators: [ComponentDecorator], + args: { + title: 'H3 title', + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + decorators: [ComponentDecorator], +}; diff --git a/yarn.lock b/yarn.lock index aa10f5b47f..7f3172c81a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15677,6 +15677,15 @@ __metadata: languageName: node linkType: hard +"@types/lodash.mapvalues@npm:^4.6.9": + version: 4.6.9 + resolution: "@types/lodash.mapvalues@npm:4.6.9" + dependencies: + "@types/lodash": "npm:*" + checksum: 09216965c2c64854c8c765f38f436333e931b98638a0b9d996bda7b6d538593a4cfe53cad7415d50593be48d76798763b97dc2d7925ab200dce1fa5b630ed3b4 + languageName: node + linkType: hard + "@types/lodash.merge@npm:^4.6.7": version: 4.6.9 resolution: "@types/lodash.merge@npm:4.6.9" @@ -44576,6 +44585,7 @@ __metadata: "@types/lodash.isequal": "npm:^4.5.7" "@types/lodash.isobject": "npm:^3.0.7" "@types/lodash.kebabcase": "npm:^4.1.7" + "@types/lodash.mapvalues": "npm:^4.6.9" "@types/lodash.merge": "npm:^4.6.7" "@types/lodash.pick": "npm:^4.3.7" "@types/lodash.snakecase": "npm:^4.1.7" @@ -44673,6 +44683,7 @@ __metadata: lodash.isequal: "npm:^4.5.0" lodash.isobject: "npm:^3.0.2" lodash.kebabcase: "npm:^4.1.1" + lodash.mapvalues: "npm:^4.6.0" lodash.merge: "npm:^4.6.2" lodash.omit: "npm:^4.5.0" lodash.pick: "npm:^4.4.0"