feat: fix dates, attachments

This commit is contained in:
Nevo David 2024-03-13 23:05:46 +07:00
parent 4100fdfeb7
commit 3bd2fbdb56
10 changed files with 226 additions and 85 deletions

BIN
apps/docs/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
apps/docs/favicon.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -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 (
<html>
<html className={inter.className}>
<head>
<link rel="icon" href="/favicon.png" sizes="any" />
</head>

View File

@ -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'}
/>
<button
onClick={askClose}
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
type="button"
>
<svg
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
>
<path
d="M11.7816 4.03157C12.0062 3.80702 12.0062 3.44295 11.7816 3.2184C11.5571 2.99385 11.193 2.99385 10.9685 3.2184L7.50005 6.68682L4.03164 3.2184C3.80708 2.99385 3.44301 2.99385 3.21846 3.2184C2.99391 3.44295 2.99391 3.80702 3.21846 4.03157L6.68688 7.49999L3.21846 10.9684C2.99391 11.193 2.99391 11.557 3.21846 11.7816C3.44301 12.0061 3.80708 12.0061 4.03164 11.7816L7.50005 8.31316L10.9685 11.7816C11.193 12.0061 11.5571 12.0061 11.7816 11.7816C12.0062 11.557 12.0062 11.193 11.7816 10.9684L8.31322 7.49999L11.7816 4.03157Z"
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
></path>
</svg>
</button>
<div className="absolute h-[57px] right-0 top-0 flex justify-center items-center">
<DatePicker onChange={setDateState} date={dateState} />
</div>
{!existingData.integration && (
<PickPlatforms
@ -328,7 +315,7 @@ export const AddEditModal: FC<{
.getCommands()
.filter((f) => f.name !== 'image'),
newImage,
postSelector(date),
postSelector(dateState),
]}
value={p.content}
preview="edit"
@ -421,6 +408,12 @@ export const AddEditModal: FC<{
<div className="relative h-[68px] flex flex-col rounded-[4px] border border-[#172034] bg-[#0B101B]">
<div className="flex flex-1 gap-[10px] relative">
<div className="absolute w-full h-full flex gap-[10px] justify-end items-center right-[16px]">
<Button
className="bg-transparent text-inputText"
onClick={askClose}
>
Cancel
</Button>
{!!existingData.integration && (
<Button
onClick={schedule('delete')}
@ -495,7 +488,7 @@ export const AddEditModal: FC<{
<ProvidersOptions
integrations={selectedIntegrations}
editorValue={value}
date={date}
date={dateState}
/>
</div>
)}

View File

@ -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<HTMLDivElement>(() => {
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 (
<div
className="flex gap-[8px] items-center relative px-[16px] select-none"
onClick={changeShow}
ref={ref}
>
<div className="cursor-pointer">{date.format('DD/MM/YYYY HH:mm')}</div>
<div className="cursor-pointer">
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="21"
viewBox="0 0 20 21"
fill="none"
>
<path
d="M16.25 3H14.375V2.375C14.375 2.20924 14.3092 2.05027 14.1919 1.93306C14.0747 1.81585 13.9158 1.75 13.75 1.75C13.5842 1.75 13.4253 1.81585 13.3081 1.93306C13.1908 2.05027 13.125 2.20924 13.125 2.375V3H6.875V2.375C6.875 2.20924 6.80915 2.05027 6.69194 1.93306C6.57473 1.81585 6.41576 1.75 6.25 1.75C6.08424 1.75 5.92527 1.81585 5.80806 1.93306C5.69085 2.05027 5.625 2.20924 5.625 2.375V3H3.75C3.41848 3 3.10054 3.1317 2.86612 3.36612C2.6317 3.60054 2.5 3.91848 2.5 4.25V16.75C2.5 17.0815 2.6317 17.3995 2.86612 17.6339C3.10054 17.8683 3.41848 18 3.75 18H16.25C16.5815 18 16.8995 17.8683 17.1339 17.6339C17.3683 17.3995 17.5 17.0815 17.5 16.75V4.25C17.5 3.91848 17.3683 3.60054 17.1339 3.36612C16.8995 3.1317 16.5815 3 16.25 3ZM16.25 6.75H3.75V4.25H5.625V4.875C5.625 5.04076 5.69085 5.19973 5.80806 5.31694C5.92527 5.43415 6.08424 5.5 6.25 5.5C6.41576 5.5 6.57473 5.43415 6.69194 5.31694C6.80915 5.19973 6.875 5.04076 6.875 4.875V4.25H13.125V4.875C13.125 5.04076 13.1908 5.19973 13.3081 5.31694C13.4253 5.43415 13.5842 5.5 13.75 5.5C13.9158 5.5 14.0747 5.43415 14.1919 5.31694C14.3092 5.19973 14.375 5.04076 14.375 4.875V4.25H16.25V6.75Z"
fill="#B69DEC"
/>
</svg>
</div>
{open && (
<div
onClick={(e) => 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"
>
<Calendar
onChange={changeDate('date')}
value={date.toDate()}
dayClassName={(date, modifiers) => {
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'
}}
/>
<TimeInput
onChange={changeDate('time')}
label="Pick time"
classNames={{
label: 'text-white py-[12px]',
input:
'bg-sixth h-[40px] border border-tableBorder text-white rounded-[4px] outline-none',
}}
placeholder="Pick time"
defaultValue={date.toDate()}
/>
<Button className="mt-[12px]" onClick={changeShow}>
Close
</Button>
</div>
)}
</div>
);
};

View File

@ -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]);

View File

@ -86,5 +86,11 @@ module.exports = {
}),
},
},
plugins: [require('tailwind-scrollbar')],
plugins: [
require('tailwind-scrollbar'),
function ({ addVariant }) {
addVariant('child', '& > *');
addVariant('child-hover', '& > *:hover');
},
],
};

View File

@ -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,
},
});
}
},
});
}
}
}

30
package-lock.json generated
View File

@ -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",

View File

@ -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",