feat: month view

This commit is contained in:
Nevo David 2024-09-08 20:27:19 +07:00
parent aab1ef1c3a
commit 9fb979687d
10 changed files with 382 additions and 341 deletions

View File

@ -48,18 +48,18 @@ export class PostsController {
@GetOrgFromRequest() org: Organization,
@Query() query: GetPostsDto
) {
const [posts, comments] = await Promise.all([
const [posts] = await Promise.all([
this._postsService.getPosts(org.id, query),
this._commentsService.getAllCommentsByWeekYear(
org.id,
query.year,
query.week
),
// this._commentsService.getAllCommentsByWeekYear(
// org.id,
// query.year,
// query.week
// ),
]);
return {
posts,
comments,
// comments,
};
}

View File

@ -34,7 +34,7 @@
--color-custom20: #121b2c;
--color-custom21: #506490;
--color-custom22: #b91c1c;
--color-custom23: #06080d;
--color-custom23: #000000;
--color-custom24: #eaff00;
--color-custom25: #2e3336;
--color-custom26: #1d9bf0;

View File

@ -12,7 +12,6 @@ import React, {
import dayjs from 'dayjs';
import { Integrations } from '@gitroom/frontend/components/launches/calendar.context';
import clsx from 'clsx';
import { commands } from '@uiw/react-md-editor';
import { usePreventWindowUnload } from '@gitroom/react/helpers/use.prevent.window.unload';
import { deleteDialog } from '@gitroom/react/helpers/delete.dialog';
import { useModals } from '@mantine/modals';
@ -27,7 +26,6 @@ import {
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import { useMoveToIntegration } from '@gitroom/frontend/components/launches/helpers/use.move.to.integration';
import { useExistingData } from '@gitroom/frontend/components/launches/helpers/use.existing.data';
import { newImage } from '@gitroom/frontend/components/launches/helpers/new.image.component';
import { MultiMediaComponent } from '@gitroom/frontend/components/media/media.component';
import { useExpend } from '@gitroom/frontend/components/launches/helpers/use.expend';
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
@ -36,7 +34,6 @@ import { ProvidersOptions } from '@gitroom/frontend/components/launches/provider
import { v4 as uuidv4 } from 'uuid';
import useSWR, { useSWRConfig } from 'swr';
import { useToaster } from '@gitroom/react/toaster/toaster';
import { postSelector } from '@gitroom/frontend/components/post-url-selector/post.url.selector';
import { UpDownArrow } from '@gitroom/frontend/components/launches/up.down.arrow';
import { DatePicker } from '@gitroom/frontend/components/launches/helpers/date.picker';
import { arrayMoveImmutable } from 'array-move';

View File

@ -21,12 +21,23 @@ import { isGeneral } from '@gitroom/react/helpers/is.general';
const CalendarContext = createContext({
currentWeek: dayjs().week(),
currentYear: dayjs().year(),
currentMonth: dayjs().month(),
comments: [] as Array<{ date: string; total: number }>,
integrations: [] as Integrations[],
trendings: [] as string[],
posts: [] as Array<Post & { integration: Integration }>,
setFilters: (filters: { currentWeek: number; currentYear: number }) => {},
changeDate: (id: string, date: dayjs.Dayjs) => {},
display: 'week',
setFilters: (filters: {
currentWeek: number;
currentYear: number;
currentMonth: number;
display: 'week' | 'month';
}) => {
/** empty **/
},
changeDate: (id: string, date: dayjs.Dayjs) => {
/** empty **/
},
});
export interface Integrations {
@ -40,28 +51,21 @@ export interface Integrations {
}
function getWeekNumber(date: Date) {
// Copy date so don't modify original
const targetDate = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
// Set to nearest Thursday: current date + 4 - current day number
// Make Sunday's day number 7
targetDate.setUTCDate(targetDate.getUTCDate() + 4 - (targetDate.getUTCDay() || 7));
// Get first day of year
const yearStart = new Date(Date.UTC(targetDate.getUTCFullYear(), 0, 1));
// Calculate full weeks to nearest Thursday
return Math.ceil((((targetDate.getTime() - yearStart.getTime()) / 86400000) + 1) / 7);
}
function isISOWeek(date: Date, weekNumber: number): boolean {
// Copy date so don't modify original
const targetDate = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
// Set to nearest Thursday: current date + 4 - current day number
// Make Sunday's day number 7
targetDate.setUTCDate(targetDate.getUTCDate() + 4 - (targetDate.getUTCDay() || 7));
// Get first day of year
const yearStart = new Date(Date.UTC(targetDate.getUTCFullYear(), 0, 1));
// Calculate full weeks to nearest Thursday
const isoWeekNo = Math.ceil((((targetDate.getTime() - yearStart.getTime()) / 86400000) + 1) / 7);
return isoWeekNo === weekNumber;
// Copy date so don't modify original
const targetDate = new Date(
Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())
);
// Set to nearest Thursday: current date + 4 - current day number
// Make Sunday's day number 7
targetDate.setUTCDate(
targetDate.getUTCDate() + 4 - (targetDate.getUTCDay() || 7)
);
// Get first day of year
const yearStart = new Date(Date.UTC(targetDate.getUTCFullYear(), 0, 1));
// Calculate full weeks to nearest Thursday
return Math.ceil(
((targetDate.getTime() - yearStart.getTime()) / 86400000 + 1) / 7
);
}
export const CalendarWeekProvider: FC<{
@ -84,20 +88,32 @@ export const CalendarWeekProvider: FC<{
})();
}, []);
const display = searchParams.get('month') ? 'month' : 'week';
const [filters, setFilters] = useState({
currentWeek: +(searchParams.get('week') || getWeekNumber(new Date())),
currentWeek:
display === 'week'
? +(searchParams.get('week') || getWeekNumber(new Date()))
: 0,
currentMonth:
display === 'week' ? 0 : +(searchParams.get('month') || dayjs().month()),
currentYear: +(searchParams.get('year') || dayjs().year()),
display,
});
const isIsoWeek = useMemo(() => {
return isISOWeek(new Date(), filters.currentWeek);
}, [filters]);
const setFiltersWrapper = useCallback(
(filters: { currentWeek: number; currentYear: number }) => {
(filters: {
currentWeek: number;
currentYear: number;
currentMonth: number;
display: 'week' | 'month';
}) => {
setFilters(filters);
router.replace(
`/launches?week=${filters.currentWeek}&year=${filters.currentYear}`
`/launches?${
filters.currentWeek
? `week=${filters.currentWeek}`
: `month=${filters.currentMonth}`
}&year=${filters.currentYear}`
);
setTimeout(() => {
mutate('/posts');
@ -107,14 +123,22 @@ export const CalendarWeekProvider: FC<{
);
const params = useMemo(() => {
return new URLSearchParams({
week: filters.currentWeek.toString(),
year: filters.currentYear.toString()
}).toString();
return new URLSearchParams(
filters.currentWeek
? {
week: filters.currentWeek.toString(),
year: filters.currentYear.toString(),
}
: {
year: filters.currentYear.toString(),
month: (filters.currentMonth + 1).toString(),
}
).toString();
}, [filters]);
const loadData = useCallback(
async (url: string) => {
setInternalData([]);
const data = (await fetch(`${url}?${params}`)).json();
return data;
},

View File

@ -1,6 +1,6 @@
'use client';
import React, { FC, useCallback, useMemo } from 'react';
import React, { FC, Fragment, useCallback, useMemo } from 'react';
import {
Integrations,
useCalendar,
@ -17,14 +17,12 @@ import { Integration, Post, State } from '@prisma/client';
import { useAddProvider } from '@gitroom/frontend/components/launches/add.provider.component';
import { CommentComponent } from '@gitroom/frontend/components/launches/comments/comment.component';
import { useSWRConfig } from 'swr';
import { useIntersectionObserver } from '@uidotdev/usehooks';
import { useToaster } from '@gitroom/react/toaster/toaster';
import { useUser } from '@gitroom/frontend/components/layout/user.context';
import { IntegrationContext } from '@gitroom/frontend/components/launches/helpers/use.integration';
import { PreviewPopup } from '@gitroom/frontend/components/marketplace/special.message';
export const days = [
'',
'Monday',
'Tuesday',
'Wednesday',
@ -33,192 +31,143 @@ export const days = [
'Saturday',
'Sunday',
];
export const hours = [
'00:00',
'01:00',
'02:00',
'03:00',
'04:00',
'05:00',
'06:00',
'07:00',
'08:00',
'09:00',
'10:00',
'11:00',
'12:00',
'13:00',
'14:00',
'15:00',
'16:00',
'17:00',
'18:00',
'19:00',
'20:00',
'21:00',
'22:00',
'23:00',
];
export const hours = Array.from({ length: 24 }, (_, i) => i);
export const Calendar = () => {
const { currentWeek, currentYear, comments } = useCalendar();
const firstDay = useMemo(() => {
return dayjs().year(currentYear).isoWeek(currentWeek).isoWeekday(1);
}, [currentYear, currentWeek]);
export const WeekView = () => {
const { currentYear, currentWeek } = useCalendar();
return (
<DNDProvider>
<div className="select-none">
<div className="grid grid-cols-8 text-center border-tableBorder border-r">
<div className="flex flex-col h-screen overflow-hidden text-textColor flex-1">
<div className="flex-1">
<div className="grid grid-cols-8 bg-customColor31 gap-[1px] border-customColor31 border rounded-[10px]">
<div className="bg-customColor20 sticky top-0 z-10 bg-gray-900"></div>
{days.map((day, index) => (
<div
className="border-tableBorder gap-[4px] border-l border-b h-[36px] border-t flex items-center justify-center bg-input text-[14px] sticky top-0 z-[100]"
key={day}
className="sticky top-0 z-10 bg-customColor20 p-2 text-center"
>
<div>{day} </div>
<div className="text-[12px]">
{day && `(${firstDay.add(index - 1, 'day').format('DD/MM')})`}
</div>
<div>{day}</div>
</div>
))}
{hours.map((hour) =>
days.map((day, index) => (
<>
{index === 0 ? (
<div
className="border-tableBorder border-l border-b h-[216px]"
key={day + hour}
>
{['00', '10', '20', '30', '40', '50'].map((num) => (
<div
key={day + hour + num}
className="h-[calc(216px/6)] text-[12px] flex justify-center items-center"
>
{hour.split(':')[0] + ':' + num}
</div>
))}
</div>
) : (
<div
className="group relative border-tableBorder border-l border-b h-[216px] flex flex-col overflow-hidden"
key={day + hour}
>
<CommentBox
totalComments={
comments.find(
(p) =>
dayjs
.utc(p.date)
.local()
.format('YYYY-MM-DD HH:mm') ===
dayjs()
.isoWeek(currentWeek)
.isoWeekday(index + 1)
.hour(+hour.split(':')[0] - 1)
.minute(0)
.format('YYYY-MM-DD HH:mm')
)?.total || 0
}
date={dayjs()
.isoWeek(currentWeek)
.isoWeekday(index + 1)
.hour(+hour.split(':')[0] - 1)
.minute(0)}
{hours.map((hour) => (
<Fragment key={hour}>
<div className="p-2 pr-4 bg-secondary text-center items-center justify-center flex">
{hour.toString().padStart(2, '0')}:00
</div>
{days.map((day, indexDay) => (
<Fragment key={`${day}-${hour}`}>
<div className="relative bg-secondary">
<CalendarColumn
getDate={dayjs()
.year(currentYear)
.week(currentWeek)
.day(indexDay + 1)
.hour(hour)
.startOf('hour')}
/>
{['00', '10', '20', '30', '40', '50'].map((num) => (
<CalendarColumn
key={day + hour + num + currentWeek + currentYear}
day={index}
hour={hour.split(':')[0] + ':' + num}
/>
))}
</div>
)}
</>
))
)}
</Fragment>
))}
</Fragment>
))}
</div>
</div>
</div>
);
};
export const MonthView = () => {
const { currentYear, currentMonth } = useCalendar();
const calendarDays = useMemo(() => {
const startOfMonth = dayjs(new Date(currentYear, currentMonth, 1));
// Calculate the day offset for Monday (isoWeekday() returns 1 for Monday)
const startDayOfWeek = startOfMonth.isoWeekday(); // 1 for Monday, 7 for Sunday
const daysBeforeMonth = startDayOfWeek - 1; // Days to show from the previous month
// Get the start date (Monday of the first week that includes this month)
const startDate = startOfMonth.subtract(daysBeforeMonth, 'day');
// Create an array to hold the calendar days (6 weeks * 7 days = 42 days max)
const calendarDays = [];
let currentDay = startDate;
for (let i = 0; i < 42; i++) {
let label = 'current-month';
if (currentDay.month() < currentMonth) label = 'previous-month';
if (currentDay.month() > currentMonth) label = 'next-month';
calendarDays.push({
day: currentDay,
label,
});
// Move to the next day
currentDay = currentDay.add(1, 'day');
}
return calendarDays;
}, [currentYear, currentMonth]);
return (
<div className="flex flex-col h-screen overflow-hidden text-textColor flex-1">
<div className="flex-1 flex">
<div className="grid grid-cols-7 grid-rows-[40px_auto] bg-customColor31 gap-[1px] border-customColor31 border rounded-[10px] flex-1">
{days.map((day) => (
<div
key={day}
className="sticky top-0 z-10 bg-customColor20 p-2 text-center"
>
<div>{day}</div>
</div>
))}
{calendarDays.map((date, index) => (
<div
key={index}
className="bg-secondary text-center items-center justify-center flex min-h-[100px]"
>
<CalendarColumn
getDate={dayjs(date.day).endOf('day')}
randomHour={true}
/>
</div>
))}
</div>
</div>
</div>
);
};
export const Calendar = () => {
const { display } = useCalendar();
return (
<DNDProvider>
{display === 'week' ? <WeekView /> : <MonthView />}
</DNDProvider>
);
};
// export const CalendarColumn: FC<{ day: number; hour: string }> = (props) => {
// const { day, hour } = props;
// const { currentWeek, currentYear } = useCalendar();
//
// const getDate = useMemo(() => {
// const date =
// dayjs()
// .year(currentYear)
// .isoWeek(currentWeek)
// .isoWeekday(day)
// .format('YYYY-MM-DD') +
// 'T' +
// hour +
// ':00';
// return dayjs(date);
// }, [currentWeek]);
//
// const isBeforeNow = useMemo(() => {
// return getDate.isBefore(dayjs());
// }, [getDate]);
//
// const [ref, entry] = useIntersectionObserver({
// threshold: 0.5,
// root: null,
// rootMargin: '0px',
// });
//
// return (
// <div className="w-full h-full" ref={ref}>
// {!entry?.isIntersecting ? (
// <div />
// ) : (
// <CalendarColumnRender {...props} />
// )}
// </div>
// );
// };
export const CalendarColumn: FC<{ day: number; hour: string }> = (props) => {
const { day, hour } = props;
export const CalendarColumn: FC<{
getDate: dayjs.Dayjs;
randomHour?: boolean;
}> = (props) => {
const { getDate, randomHour } = props;
const user = useUser();
const {
currentWeek,
currentYear,
integrations,
posts,
trendings,
changeDate,
} = useCalendar();
const { integrations, posts, trendings, changeDate, display } = useCalendar();
const toaster = useToaster();
const modal = useModals();
const fetch = useFetch();
const getDate = useMemo(() => {
const date =
dayjs()
.year(currentYear)
.week(currentWeek)
.day(day + 1)
.format('YYYY-MM-DD') +
'T' +
hour +
':00';
return dayjs(date);
}, [currentWeek]);
const postList = useMemo(() => {
return posts.filter((post) => {
return dayjs
.utc(post.publishDate)
.local()
.isBetween(getDate, getDate.add(59, 'minute'), 'minute', '[)');
const pList = dayjs.utc(post.publishDate).local();
return display === 'week'
? pList.isBetween(getDate.startOf('hour'), getDate.endOf('hour'))
: pList.format('DD/MM/YYYY') === getDate.format('DD/MM/YYYY');
});
}, [posts]);
}, [posts, display, getDate]);
const canBeTrending = useMemo(() => {
return !!trendings.find((trend) => {
@ -351,7 +300,9 @@ export const CalendarColumn: FC<{ day: number; hour: string }> = (props) => {
children: (
<AddEditModal
integrations={integrations.slice(0).map((p) => ({ ...p }))}
date={getDate}
date={
randomHour ? getDate.hour(Math.floor(Math.random() * 24)) : getDate
}
reopenModal={() => ({})}
/>
),
@ -363,70 +314,85 @@ export const CalendarColumn: FC<{ day: number; hour: string }> = (props) => {
const addProvider = useAddProvider();
return (
<div className={clsx("relative flex flex-col w-full min-h-full", canDrop && 'bg-white/80')} ref={drop}>
<div className="flex flex-col w-full min-h-full">
{display === 'month' && (
<div className={clsx('pt-[5px]', isBeforeNow && 'bg-customColor23')}>
{getDate.date()}
</div>
)}
<div
{...(canBeTrending
? {
'data-tooltip-id': 'tooltip',
'data-tooltip-content': 'Predicted GitHub Trending Change',
}
: {})}
className={clsx(
'flex-col flex-1 text-[12px] pointer w-full cursor-pointer overflow-hidden justify-center overflow-x-auto flex scrollbar scrollbar-thumb-tableBorder scrollbar-track-secondary',
isBeforeNow && 'bg-customColor23',
canBeTrending && 'bg-customColor24'
'relative flex flex-col flex-1',
canDrop && 'bg-white/80'
)}
ref={drop}
>
{postList.map((post) => (
<div
key={post.id}
className={clsx(
'text-textColor p-[2.5px] relative flex flex-col justify-center items-center'
)}
>
<div className="relative w-full flex flex-col items-center p-[2.5px]">
<CalendarItem
date={getDate}
state={post.state}
editPost={editPost(post)}
post={post}
integrations={integrations}
<div
{...(canBeTrending
? {
'data-tooltip-id': 'tooltip',
'data-tooltip-content': 'Predicted GitHub Trending Change',
}
: {})}
className={clsx(
'flex-col text-[12px] pointer w-full cursor-pointer overflow-hidden overflow-x-auto flex scrollbar scrollbar-thumb-tableBorder scrollbar-track-secondary',
isBeforeNow && 'bg-customColor23 flex-1',
canBeTrending && 'bg-customColor24'
)}
>
{postList.map((post) => (
<div
key={post.id}
className={clsx(
'text-textColor p-[2.5px] relative flex flex-col justify-center items-center'
)}
>
<div className="relative w-full flex flex-col items-center p-[2.5px]">
<CalendarItem
isBeforeNow={isBeforeNow}
date={getDate}
state={post.state}
editPost={editPost(post)}
post={post}
integrations={integrations}
/>
</div>
</div>
))}
</div>
{!isBeforeNow && (
<div className="pb-[2.5px] px-[5px] flex-1 flex" onClick={integrations.length ? addModal : addProvider}>
<div
className={clsx(
display === 'month' ? 'flex-1 min-h-[40px]' :
!postList.length
? 'h-full w-full absolute left-0 top-0 p-[5px]'
: 'h-[40px]',
'flex items-center justify-center cursor-pointer pb-[2.5px]'
)}
>
<div
className={clsx(
'hover:before:content-["+"] w-full h-full text-seventh rounded-[10px] hover:border hover:border-seventh flex justify-center items-center'
)}
/>
</div>
</div>
))}
)}
</div>
{!isBeforeNow && (
<div className="pb-[2.5px] px-[5px]">
<div
className={clsx(
!postList.length
? 'h-full w-full absolute left-0 top-0 p-[5px]'
: 'h-[40px]',
'flex items-center justify-center cursor-pointer pb-[2.5px]'
)}
>
<div
onClick={integrations.length ? addModal : addProvider}
className={clsx(
'hover:before:content-["+"] w-full h-full text-seventh rounded-[10px] hover:border hover:border-seventh flex justify-center items-center'
)}
/>
</div>
</div>
)}
</div>
);
};
const CalendarItem: FC<{
date: dayjs.Dayjs;
isBeforeNow: boolean;
editPost: () => void;
integrations: Integrations[];
state: State;
post: Post & { integration: Integration };
}> = (props) => {
const { editPost, post, date, integrations, state } = props;
const { editPost, post, date, isBeforeNow, state } = props;
const [{ opacity }, dragRef] = useDrag(
() => ({
type: 'post',
@ -444,7 +410,7 @@ const CalendarItem: FC<{
className={clsx(
'gap-[5px] w-full flex h-full flex-1 rounded-[10px] border border-seventh px-[5px] p-[2.5px]',
'relative',
state === 'DRAFT' && '!grayscale'
(state === 'DRAFT' || isBeforeNow) && '!grayscale'
)}
style={{ opacity }}
>
@ -458,7 +424,10 @@ const CalendarItem: FC<{
src={`/icons/platforms/${post.integration?.providerIdentifier}.png`}
/>
</div>
<div className="whitespace-pre-wrap line-clamp-3">{post.content}</div>
<div className="whitespace-pre-wrap line-clamp-3">
{state === 'DRAFT' ? 'Draft: ' : ''}
{post.content}
</div>
</div>
);
};

View File

@ -1,32 +1,109 @@
'use client';
import { useCalendar } from '@gitroom/frontend/components/launches/calendar.context';
import clsx from 'clsx';
import dayjs from 'dayjs';
import {useCallback} from "react";
import { useCallback } from 'react';
export const Filters = () => {
const week = useCalendar();
const betweenDates =
dayjs().year(week.currentYear).isoWeek(week.currentWeek).startOf('isoWeek').format('DD/MM/YYYY') +
' - ' +
dayjs().year(week.currentYear).isoWeek(week.currentWeek).endOf('isoWeek').format('DD/MM/YYYY');
week.display === 'week'
? dayjs()
.year(week.currentYear)
.isoWeek(week.currentWeek)
.startOf('isoWeek')
.format('DD/MM/YYYY') +
' - ' +
dayjs()
.year(week.currentYear)
.isoWeek(week.currentWeek)
.endOf('isoWeek')
.format('DD/MM/YYYY')
: dayjs()
.year(week.currentYear)
.month(week.currentMonth)
.startOf('month')
.format('DD/MM/YYYY') +
' - ' +
dayjs()
.year(week.currentYear)
.month(week.currentMonth)
.endOf('month')
.format('DD/MM/YYYY');
const nextWeek = useCallback(() => {
week.setFilters({
currentWeek: week.currentWeek === 52 ? 1 : week.currentWeek + 1,
currentYear: week.currentWeek === 52 ? week.currentYear + 1 : week.currentYear,
});
}, [week.currentWeek, week.currentYear]);
const setWeek = useCallback(() => {
week.setFilters({
currentWeek: dayjs().isoWeek(),
currentYear: dayjs().year(),
currentMonth: 0,
display: 'week',
});
}, [week]);
const previousWeek = useCallback(() => {
week.setFilters({
currentWeek: week.currentWeek === 1 ? 52 : week.currentWeek - 1,
currentYear: week.currentWeek === 1 ? week.currentYear - 1 : week.currentYear,
});
}, [week.currentWeek, week.currentYear]);
const setMonth = useCallback(() => {
week.setFilters({
currentMonth: dayjs().month(),
currentWeek: 0,
currentYear: dayjs().year(),
display: 'month',
});
}, [week]);
const next = useCallback(() => {
week.setFilters({
currentWeek:
week.display === 'week'
? week.currentWeek === 52
? 1
: week.currentWeek + 1
: 0,
currentYear:
week.display === 'week'
? week.currentWeek === 52
? week.currentYear + 1
: week.currentYear
: week.currentMonth === 11
? week.currentYear + 1
: week.currentYear,
display: week.display as any,
currentMonth:
week.display === 'week'
? 0
: week.currentMonth === 11
? 0
: week.currentMonth + 1,
});
}, [week.display, week.currentMonth, week.currentWeek, week.currentYear]);
const previous = useCallback(() => {
week.setFilters({
currentWeek:
week.display === 'week'
? week.currentWeek === 1
? 52
: week.currentWeek - 1
: 0,
currentYear:
week.display === 'week'
? week.currentWeek === 1
? week.currentYear - 1
: week.currentYear
: week.currentMonth === 0
? week.currentYear - 1
: week.currentYear,
display: week.display as any,
currentMonth:
week.display === 'week'
? 0
: week.currentMonth === 0
? 11
: week.currentMonth - 1,
});
}, [week.display, week.currentMonth, week.currentWeek, week.currentYear]);
return (
<div className="h-[20px] text-textColor flex gap-[8px] items-center select-none">
<div onClick={previousWeek}>
<div className="text-textColor flex gap-[8px] items-center select-none">
<div onClick={previous}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
@ -40,8 +117,12 @@ export const Filters = () => {
/>
</svg>
</div>
<div>Week {week.currentWeek}</div>
<div onClick={nextWeek}>
<div className="w-[80px] text-center">
{week.display === 'week'
? `Week ${week.currentWeek}`
: `${dayjs().month(week.currentMonth).format('MMMM')}`}
</div>
<div onClick={next}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
@ -55,7 +136,25 @@ export const Filters = () => {
/>
</svg>
</div>
<div>{betweenDates}</div>
<div className="flex-1">{betweenDates}</div>
<div
className={clsx(
'border border-tableBorder p-[10px]',
week.display === 'week' && 'bg-tableBorder'
)}
onClick={setWeek}
>
Week
</div>
<div
className={clsx(
'border border-tableBorder p-[10px]',
week.display === 'month' && 'bg-tableBorder'
)}
onClick={setMonth}
>
Month
</div>
</div>
);
};

View File

@ -13,13 +13,12 @@ import { LoadingComponent } from '@gitroom/frontend/components/layout/loading';
import clsx from 'clsx';
import { useUser } from '../layout/user.context';
import { Menu } from '@gitroom/frontend/components/launches/menu/menu';
import { GeneratorComponent } from '@gitroom/frontend/components/launches/generator/generator';
import { useRouter, useSearchParams } from 'next/navigation';
import { Integration } from '@prisma/client';
import ImageWithFallback from '@gitroom/react/helpers/image.with.fallback';
import { useToaster } from '@gitroom/react/toaster/toaster';
import { useFireEvents } from '@gitroom/helpers/utils/use.fire.events';
import { NewCalendarComponent } from '@gitroom/frontend/components/launches/new.calendar.component';
import { Calendar } from './calendar';
export const LaunchesComponent = () => {
const fetch = useFetch();
@ -117,7 +116,7 @@ export const LaunchesComponent = () => {
<CalendarWeekProvider integrations={sortedIntegrations}>
<div className="flex flex-1 flex-col">
<div className="flex flex-1 relative">
<div className="outline-none absolute w-full h-full grid grid-cols-[220px_minmax(0,1fr)] gap-[30px] overflow-hidden overflow-y-auto scrollbar scrollbar-thumb-tableBorder scrollbar-track-secondary">
<div className="outline-none w-full h-full grid grid-cols-[220px_minmax(0,1fr)] gap-[30px] scrollbar scrollbar-thumb-tableBorder scrollbar-track-secondary">
<div className="w-[220px] bg-third p-[16px] flex flex-col gap-[24px] min-h-[100%]">
<h2 className="text-[20px]">Channels</h2>
<div className="gap-[16px] flex flex-col">
@ -213,8 +212,7 @@ export const LaunchesComponent = () => {
</div>
<div className="flex-1 flex flex-col gap-[14px]">
<Filters />
<NewCalendarComponent />
{/*<Calendar />*/}
<Calendar />
</div>
</div>
</div>

View File

@ -1,54 +0,0 @@
'use client';
import { Fragment } from 'react';
import { CalendarColumn } from '@gitroom/frontend/components/launches/calendar';
import { DNDProvider } from '@gitroom/frontend/components/launches/helpers/dnd.provider';
export const days = [
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday',
];
export const hours = Array.from({ length: 24 }, (_, i) => i);
export const NewCalendarComponent = () => {
return (
<DNDProvider>
<div className="flex flex-col h-screen overflow-hidden text-textColor flex-1">
<div className="flex-1">
<div className="grid grid-cols-8 bg-customColor31 gap-[1px] border-customColor31 border rounded-[10px]">
<div className="bg-customColor20 sticky top-0 z-10 bg-gray-900"></div>
{days.map((day, index) => (
<div
key={day}
className="sticky top-0 z-10 bg-customColor20 p-2 text-center"
>
<div>{day}</div>
</div>
))}
{hours.map((hour) => (
<Fragment key={hour}>
<div className="p-2 pr-4 bg-secondary text-center items-center justify-center flex">
{hour.toString().padStart(2, '0')}:00
</div>
{days.map((day, indexDay) => (
<Fragment key={`${day}-${hour}`}>
<div className="relative bg-secondary">
<CalendarColumn
day={indexDay}
hour={`${hour.toString().padStart(2, '0')}:00`}
/>
</div>
</Fragment>
))}
</Fragment>
))}
</div>
</div>
</div>
</DNDProvider>
);
};

View File

@ -64,10 +64,10 @@ export class PostsRepository {
getPosts(orgId: string, query: GetPostsDto) {
const dateYear = dayjs().year(query.year);
const date = dateYear.isoWeek(query.week);
const date = query.week ? dateYear.isoWeek(query.week) : dateYear.month(query.month-1);
const startDate = date.startOf('isoWeek').subtract(2, 'days').toDate();
const endDate = date.endOf('isoWeek').add(2, 'days').toDate();
const startDate = (query.week ? date.startOf('isoWeek') : date.startOf('month')).subtract(2, 'days').toDate();
const endDate = (query.week ? date.endOf('isoWeek') : date.endOf('month')).add(2, 'days').toDate();
return this._post.model.post.findMany({
where: {

View File

@ -1,14 +1,22 @@
import { Type } from 'class-transformer';
import { IsIn, IsNumber, IsString, Max, Min } from 'class-validator';
import { IsIn, IsNumber, IsString, Max, Min, ValidateIf } from 'class-validator';
import dayjs from 'dayjs';
export class GetPostsDto {
@ValidateIf((o) => !o.month)
@Type(() => Number)
@IsNumber()
@Max(52)
@Min(1)
week: number;
@ValidateIf((o) => !o.week)
@Type(() => Number)
@IsNumber()
@Max(52)
@Min(1)
month: number;
@Type(() => Number)
@IsNumber()
@Max(dayjs().add(10, 'year').year())