diff --git a/apps/docs/favicon.ico b/apps/docs/favicon.ico new file mode 100644 index 00000000..317ebcb2 Binary files /dev/null and b/apps/docs/favicon.ico differ diff --git a/apps/docs/favicon.png b/apps/docs/favicon.png old mode 100644 new mode 100755 index 8f4b9758..57d731fd Binary files a/apps/docs/favicon.png and b/apps/docs/favicon.png differ diff --git a/apps/frontend/src/app/layout.tsx b/apps/frontend/src/app/layout.tsx index c239398c..968c8dae 100644 --- a/apps/frontend/src/app/layout.tsx +++ b/apps/frontend/src/app/layout.tsx @@ -5,11 +5,14 @@ import 'react-tooltip/dist/react-tooltip.css'; import LayoutContext from '@gitroom/frontend/components/layout/layout.context'; import { ReactNode } from 'react'; -import { Chakra_Petch } from 'next/font/google'; +import { Chakra_Petch, Inter } from 'next/font/google'; + const chakra = Chakra_Petch({ weight: '400', subsets: ['latin'] }); +const inter = Inter({ subsets: ['latin'], display: 'swap' }); + export default async function AppLayout({ children }: { children: ReactNode }) { return ( - + diff --git a/apps/frontend/src/components/launches/add.edit.model.tsx b/apps/frontend/src/components/launches/add.edit.model.tsx index bf4c1879..2d577eb3 100644 --- a/apps/frontend/src/components/launches/add.edit.model.tsx +++ b/apps/frontend/src/components/launches/add.edit.model.tsx @@ -37,12 +37,16 @@ import { 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'; export const AddEditModal: FC<{ date: dayjs.Dayjs; integrations: Integrations[]; }> = (props) => { const { date, integrations } = props; + const [dateState, setDateState] = useState(date); + const { mutate } = useSWRConfig(); // selected integrations to allow edit @@ -115,47 +119,47 @@ export const AddEditModal: FC<{ target: { name: string; value?: Array<{ id: string; path: string }> }; }) => { return setValue((prev) => { - prev[index].image = newValue.target.value; - return [...prev]; + return prev.map((p, i) => { + if (i === index) { + return { ...p, image: newValue.target.value }; + } + return p; + }); }); }, - [value] + [] ); // Add another editor const addValue = useCallback( (index: number) => () => { setValue((prev) => { - prev.splice(index + 1, 0, { content: '' }); - return [...prev]; + return prev.reduce((acc, p, i) => { + acc.push(p); + if (i === index) { + acc.push({ content: '' }); + } + + return acc; + }, [] as Array<{ content: string }>); }); }, - [value] + [] ); const changePosition = useCallback( (index: number) => (type: 'up' | 'down') => { if (type === 'up' && index !== 0) { setValue((prev) => { - const temp = prev[index]; - prev[index] = prev[index - 1]; - prev[index - 1] = temp; - return [...prev]; + return arrayMoveImmutable(prev, index, index - 1); }); - } else if ( - type === 'down' && - value.length !== 0 && - value.length !== index + 1 - ) { + } else if (type === 'down') { setValue((prev) => { - const temp = prev[index]; - prev[index] = prev[index + 1]; - prev[index + 1] = temp; - return [...prev]; + return arrayMoveImmutable(prev, index, index + 1); }); } }, - [value] + [] ); // Delete post @@ -249,7 +253,7 @@ export const AddEditModal: FC<{ method: 'POST', body: JSON.stringify({ type, - date: date.utc().format('YYYY-MM-DDTHH:mm:ss'), + date: dateState.utc().format('YYYY-MM-DDTHH:mm:ss'), posts: allKeys, }), }); @@ -283,26 +287,9 @@ export const AddEditModal: FC<{ title={existingData?.group ? 'Edit Post' : 'Create Post'} /> - +
+ +
{!existingData.integration && ( f.name !== 'image'), newImage, - postSelector(date), + postSelector(dateState), ]} value={p.content} preview="edit" @@ -421,6 +408,12 @@ export const AddEditModal: FC<{
+ {!!existingData.integration && (
)} diff --git a/apps/frontend/src/components/launches/helpers/date.picker.tsx b/apps/frontend/src/components/launches/helpers/date.picker.tsx new file mode 100644 index 00000000..1419b0c0 --- /dev/null +++ b/apps/frontend/src/components/launches/helpers/date.picker.tsx @@ -0,0 +1,108 @@ +import { FC, useCallback, useState } from 'react'; +import dayjs from 'dayjs'; +import { Calendar, TimeInput } from '@mantine/dates'; +import { useClickOutside } from '@mantine/hooks'; +import { Button } from '@gitroom/react/form/button'; + +export const DatePicker: FC<{ + date: dayjs.Dayjs; + onChange: (day: dayjs.Dayjs) => void; +}> = (props) => { + const { date, onChange } = props; + const [open, setOpen] = useState(false); + + const changeShow = useCallback(() => { + setOpen((prev) => !prev); + }, []); + + const ref = useClickOutside(() => { + setOpen(false); + }); + + const changeDate = useCallback( + (type: 'date' | 'time') => (day: Date) => { + console.log( + type === 'time' + ? date.format('YYYY-MM-DD') + ' ' + dayjs(day).format('HH:mm:ss') + : dayjs(day).format('YYYY-MM-DD') + ' ' + date.format('HH:mm:ss') + ); + onChange( + dayjs( + type === 'time' + ? date.format('YYYY-MM-DD') + ' ' + dayjs(day).format('HH:mm:ss') + : dayjs(day).format('YYYY-MM-DD') + ' ' + date.format('HH:mm:ss') + ) + ); + }, + [date] + ); + + return ( +
+
{date.format('DD/MM/YYYY HH:mm')}
+
+ + + +
+ {open && ( +
e.stopPropagation()} + className="animate-normalFadeDown absolute top-[100%] mt-[16px] right-0 bg-sixth border border-tableBorder text-white rounded-[16px] z-[300] p-[16px] flex flex-col" + > + { + if (modifiers.weekend) { + return '!text-[#B69DEC]'; + } + + if (modifiers.outside) { + return '!text-gray'; + } + + if (modifiers.selected) { + return '!text-white !bg-seventh !outline-none'; + } + + return '!text-white'; + }} + classNames={{ + day: 'hover:bg-seventh', + calendarHeaderControl: 'text-white hover:bg-third', + calendarHeaderLevel: 'text-white hover:bg-third', // cell: 'child:!text-white' + }} + /> + + +
+ )} +
+ ); +}; diff --git a/apps/frontend/src/components/launches/providers/high.order.provider.tsx b/apps/frontend/src/components/launches/providers/high.order.provider.tsx index 75853682..c04ba7d5 100644 --- a/apps/frontend/src/components/launches/providers/high.order.provider.tsx +++ b/apps/frontend/src/components/launches/providers/high.order.provider.tsx @@ -27,6 +27,7 @@ import clsx from 'clsx'; import { newImage } from '@gitroom/frontend/components/launches/helpers/new.image.component'; import { postSelector } from '@gitroom/frontend/components/post-url-selector/post.url.selector'; import { UpDownArrow } from '@gitroom/frontend/components/launches/up.down.arrow'; +import { arrayMoveImmutable } from 'array-move'; // Simple component to change back to settings on after changing tab export const SetTab: FC<{ changeTab: () => void }> = (props) => { @@ -145,36 +146,32 @@ export const withProvider = ( const addValue = useCallback( (index: number) => () => { setInPlaceValue((prev) => { - prev.splice(index + 1, 0, { content: '' }); - return [...prev]; + return prev.reduce((acc, p, i) => { + acc.push(p); + if (i === index) { + acc.push({ content: '' }); + } + + return acc; + }, [] as Array<{ content: string }>); }); }, - [InPlaceValue] + [] ); const changePosition = useCallback( (index: number) => (type: 'up' | 'down') => { if (type === 'up' && index !== 0) { setInPlaceValue((prev) => { - const temp = prev[index]; - prev[index] = prev[index - 1]; - prev[index - 1] = temp; - return [...prev]; + return arrayMoveImmutable(prev, index, index - 1); }); - } else if ( - type === 'down' && - InPlaceValue.length !== 0 && - InPlaceValue.length !== index + 1 - ) { + } else if (type === 'down') { setInPlaceValue((prev) => { - const temp = prev[index]; - prev[index] = prev[index + 1]; - prev[index + 1] = temp; - return [...prev]; + return arrayMoveImmutable(prev, index, index + 1); }); } }, - [InPlaceValue] + [] ); // Delete post @@ -213,7 +210,7 @@ export const withProvider = ( setInPlaceValue( editInPlace ? [{ content: '' }] - : props.value.map((p) => ({ id: p.id, content: p.content })) + : props.value.map((p) => ({ id: p.id, content: p.content, image: p.image})) ); }, [props.value, editInPlace]); diff --git a/apps/frontend/tailwind.config.js b/apps/frontend/tailwind.config.js index 8c114584..751c5f1a 100644 --- a/apps/frontend/tailwind.config.js +++ b/apps/frontend/tailwind.config.js @@ -86,5 +86,11 @@ module.exports = { }), }, }, - plugins: [require('tailwind-scrollbar')], + plugins: [ + require('tailwind-scrollbar'), + function ({ addVariant }) { + addVariant('child', '& > *'); + addVariant('child-hover', '& > *:hover'); + }, + ], }; diff --git a/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts b/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts index 8cf07362..7c8672f4 100644 --- a/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts +++ b/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts @@ -213,28 +213,30 @@ export class PostsService { post ); - if (posts?.length) { - await this._workerServiceProducer.delete( - 'post', - previousPost ? previousPost : posts?.[0]?.id - ); - if ( - (body.type === 'schedule' || body.type === 'now') && - dayjs(body.date).isAfter(dayjs()) - ) { - this._workerServiceProducer.emit('post', { + if (!posts?.length) { + return; + } + + await this._workerServiceProducer.delete( + 'post', + previousPost ? previousPost : posts?.[0]?.id + ); + if ( + (body.type === 'schedule' || body.type === 'now') && + dayjs(body.date).isAfter(dayjs()) + ) { + this._workerServiceProducer.emit('post', { + id: posts[0].id, + options: { + delay: + body.type === 'now' + ? 0 + : dayjs(posts[0].publishDate).diff(dayjs(), 'millisecond'), + }, + payload: { id: posts[0].id, - options: { - delay: - body.type === 'now' - ? 0 - : dayjs(posts[0].publishDate).diff(dayjs(), 'millisecond'), - }, - payload: { - id: posts[0].id, - }, - }); - } + }, + }); } } } diff --git a/package-lock.json b/package-lock.json index d0e8b20e..ee009967 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@casl/ability": "^6.5.0", "@hookform/resolvers": "^3.3.4", "@mantine/core": "^5.10.5", + "@mantine/dates": "^5.10.5", "@mantine/hooks": "^5.10.5", "@mantine/modals": "^5.10.5", "@nestjs/cache-manager": "^2.2.1", @@ -40,6 +41,7 @@ "@uidotdev/usehooks": "^2.4.1", "@uiw/react-md-editor": "^4.0.3", "@virtual-grid/react": "^2.0.2", + "array-move": "^4.0.0", "axios": "1.6.7", "bcrypt": "^5.1.1", "bufferutil": "^4.0.8", @@ -148,6 +150,9 @@ "url-loader": "^4.1.1", "vite": "^5.0.0", "vitest": "1.3.1" + }, + "engines": { + "node": ">=20.0.0 <21.0.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -4397,6 +4402,20 @@ "react-dom": ">=16.8.0" } }, + "node_modules/@mantine/dates": { + "version": "5.10.5", + "resolved": "https://registry.npmjs.org/@mantine/dates/-/dates-5.10.5.tgz", + "integrity": "sha512-l7lSgDKEV+phTgUAHIkc/22Qgq+WBg0P7JS2WpeZeERX8eyD4BGlsY3ZWqHigYxhBq/Ycd2tHZFmwl2p+694Zw==", + "dependencies": { + "@mantine/utils": "5.10.5" + }, + "peerDependencies": { + "@mantine/core": "5.10.5", + "@mantine/hooks": "5.10.5", + "dayjs": ">=1.0.0", + "react": ">=16.8.0" + } + }, "node_modules/@mantine/hooks": { "version": "5.10.5", "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-5.10.5.tgz", @@ -13221,6 +13240,17 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/array-move": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/array-move/-/array-move-4.0.0.tgz", + "integrity": "sha512-+RY54S8OuVvg94THpneQvFRmqWdAHeqtMzgMW6JNurHxe8rsS07cHQdfGkXnTUXiBcyZ0j3SiDIxxj0RPiqCkQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/array-timsort": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", diff --git a/package.json b/package.json index 432a8eed..d1a3cbe8 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@casl/ability": "^6.5.0", "@hookform/resolvers": "^3.3.4", "@mantine/core": "^5.10.5", + "@mantine/dates": "^5.10.5", "@mantine/hooks": "^5.10.5", "@mantine/modals": "^5.10.5", "@nestjs/cache-manager": "^2.2.1", @@ -44,6 +45,7 @@ "@uidotdev/usehooks": "^2.4.1", "@uiw/react-md-editor": "^4.0.3", "@virtual-grid/react": "^2.0.2", + "array-move": "^4.0.0", "axios": "1.6.7", "bcrypt": "^5.1.1", "bufferutil": "^4.0.8",