feat: remove mentine modals with custom modals, fix reddit

This commit is contained in:
Nevo David 2025-09-14 19:56:27 +07:00
parent 9ab19f50e8
commit ac16e5211c
52 changed files with 920 additions and 757 deletions

View File

@ -22,7 +22,8 @@
--new-col-color: #2c2b2b;
--new-menu-dots: #696868;
--new-menu-hover: #fff;
--menu-shadow: 0 8px 30px 0 rgba(0, 0, 0, 0.50);
--menu-shadow: 0 8px 30px 0 rgba(0, 0, 0, 0.5);
--popup-color: rgba(65, 64, 66, 0.3);
}
.light {
--new-bgColor: #f0f2f4;
@ -33,8 +34,8 @@
--new-boxFocused: #ebe8ff;
--new-textColor: 14 14 14;
--new-blockSeparator: #f2f2f4;
--new-btn-simple: #ECEEF1;
--new-btn-text: #0E0E0E;
--new-btn-simple: #eceef1;
--new-btn-text: #0e0e0e;
--new-btn-primary: #612bd3;
--new-ai-btn: #d82d7e;
--new-box-hover: #f4f6f8;
@ -43,15 +44,19 @@
--new-table-text: #777b7f;
--new-table-text-focused: #fc69ff;
--new-small-strips: #191818;
--new-big-strips: #F5F7F9;
--new-col-color: #EFF1F3;
--new-big-strips: #f5f7f9;
--new-col-color: #eff1f3;
--new-menu-dots: #696868;
--new-menu-hover: #000;
--menu-shadow: -22px 83px 24px 0 rgba(55, 52, 75, 0.00), -14px 53px 22px 0 rgba(55, 52, 75, 0.01), -8px 30px 19px 0 rgba(55, 52, 75, 0.05), -3px 13px 14px 0 rgba(55, 52, 75, 0.09), -1px 3px 8px 0 rgba(55, 52, 75, 0.10);
--menu-shadow: -22px 83px 24px 0 rgba(55, 52, 75, 0),
-14px 53px 22px 0 rgba(55, 52, 75, 0.01),
-8px 30px 19px 0 rgba(55, 52, 75, 0.05),
-3px 13px 14px 0 rgba(55, 52, 75, 0.09),
-1px 3px 8px 0 rgba(55, 52, 75, 0.1);
--popup-color: rgba(55, 37, 97, 0.2);
}
}
:root {
.dark {
--color-primary: #0e0e0e;
@ -193,4 +198,4 @@
--color-custom55: #d5d7e1;
--color-modalCustom: transparent;
}
}
}

View File

@ -357,6 +357,10 @@ body * {
// /*right: -5rem !important;*/
//}
.trz {
transform: translateZ(0);
}
.uppy-FileInput-container {
@apply cursor-pointer font-[500] flex justify-center items-center gap-[4px] text-[12px] rounded-[4px] w-[107px] h-[25px] text-textColor border-[2px];
@apply bg-customColor3 border-customColor21;
@ -672,3 +676,6 @@ html[dir='rtl'] [dir='ltr'] {
}
}
}
.blur-xs {
filter: blur(4px);
}

View File

@ -2,7 +2,7 @@ import React, { FC, Fragment, useCallback, useMemo, useState } from 'react';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import useSWR from 'swr';
import { Button } from '@gitroom/react/form/button';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import { Input } from '@gitroom/react/form/input';
import { FormProvider, useForm } from 'react-hook-form';
@ -28,11 +28,8 @@ export const Autopost: FC = () => {
const addWebhook = useCallback(
(data?: any) => () => {
modal.openModal({
title: '',
withCloseButton: false,
classNames: {
modal: 'bg-transparent text-textColor',
},
title: data ? 'Edit Autopost' : 'Add Autopost',
withCloseButton: true,
children: <AddOrEditWebhook data={data} reload={mutate} />,
});
},
@ -296,29 +293,7 @@ export const AddOrEditWebhook: FC<{
return (
<FormProvider {...form}>
<form onSubmit={form.handleSubmit(callBack)}>
<div className="relative flex gap-[20px] flex-col flex-1 rounded-[4px] border border-customColor6 bg-sixth p-[16px] pt-0 w-[500px]">
<TopTitle title={data ? 'Edit autopost' : 'Add autopost'} />
<button
className="outline-none absolute end-[20px] top-[15px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
type="button"
onClick={modal.closeAll}
>
<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="relative flex gap-[20px] flex-col flex-1 rounded-[4px] border border-customColor6 pt-0">
<div>
<Input
label="Title"

View File

@ -17,7 +17,7 @@ import { useSWRConfig } from 'swr';
import { useUser } from '@gitroom/frontend/components/layout/user.context';
import { useRouter, useSearchParams } from 'next/navigation';
import { useVariables } from '@gitroom/react/helpers/variable.context';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import { Textarea } from '@gitroom/react/form/textarea';
import { useFireEvents } from '@gitroom/helpers/utils/use.fire.events';

View File

@ -1,6 +1,6 @@
'use client';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import React, { FC, useCallback, useEffect, useMemo } from 'react';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import { Input } from '@gitroom/react/form/input';
@ -24,17 +24,9 @@ export const useAddProvider = (update?: () => void) => {
return useCallback(async () => {
const data = await (await fetch('/integrations')).json();
modal.openModal({
title: '',
withCloseButton: false,
classNames: {
modal: 'text-textColor',
},
size: 'auto',
children: (
<ModalWrapperComponent title="Add Channel">
<AddProviderComponent update={update} {...data} />
</ModalWrapperComponent>
),
title: 'Add Channel',
withCloseButton: true,
children: <AddProviderComponent update={update} {...data} />,
});
}, []);
};
@ -349,20 +341,18 @@ export const AddProviderComponent: FC<{
await fetch(`/integrations/social/${identifier}`)
).json();
modal.openModal({
title: '',
title: 'Web3 provider',
withCloseButton: false,
classNames: {
modal: 'bg-transparent text-textColor',
},
children: (
<ModalWrapperComponent title="Web3 provider">
<Web3Providers
onComplete={(code, newState) => {
window.location.href = `/integrations/social/${identifier}?code=${code}&state=${newState}`;
}}
nonce={url}
/>
</ModalWrapperComponent>
<Web3Providers
onComplete={(code, newState) => {
window.location.href = `/integrations/social/${identifier}?code=${code}&state=${newState}`;
}}
nonce={url}
/>
),
});
return;
@ -388,35 +378,29 @@ export const AddProviderComponent: FC<{
if (isExternal) {
modal.closeAll();
modal.openModal({
title: '',
title: 'URL',
withCloseButton: false,
classNames: {
modal: 'bg-transparent text-textColor',
},
children: (
<ModalWrapperComponent title="URL">
<UrlModal gotoUrl={gotoIntegration} />
</ModalWrapperComponent>
),
children: <UrlModal gotoUrl={gotoIntegration} />,
});
return;
}
if (customFields) {
modal.closeAll();
modal.openModal({
title: '',
title: 'Add Provider',
withCloseButton: false,
classNames: {
modal: 'bg-transparent text-textColor',
},
children: (
<ModalWrapperComponent title="Add Provider">
<CustomVariables
identifier={identifier}
gotoUrl={(url: string) => router.push(url)}
variables={customFields}
/>
</ModalWrapperComponent>
<CustomVariables
identifier={identifier}
gotoUrl={(url: string) => router.push(url)}
variables={customFields}
/>
),
});
return;
@ -425,9 +409,7 @@ export const AddProviderComponent: FC<{
},
[]
);
const close = useCallback(() => {
modal.closeAll();
}, []);
const showApiButton = useCallback(
(identifier: string, name: string) => async () => {
modal.openModal({
@ -449,7 +431,6 @@ export const AddProviderComponent: FC<{
return (
<div className="w-full flex flex-col gap-[20px] rounded-[4px] relative">
<div className="flex flex-col">
<h2 className="pt-[16px] pb-[10px]">{t('social', 'Social')}</h2>
<div className="grid grid-cols-5 gap-[10px] justify-items-center justify-center">
{social.map((item) => (
<div

View File

@ -1,7 +1,7 @@
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import React, { FC, FormEventHandler, useCallback, useState } from 'react';
import { Integrations } from '@gitroom/frontend/components/launches/calendar.context';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { Input } from '@gitroom/react/form/input';
import { Button } from '@gitroom/react/form/button';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';

View File

@ -30,7 +30,7 @@ import 'dayjs/locale/ar';
import 'dayjs/locale/tr';
import 'dayjs/locale/vi';
import localizedFormat from 'dayjs/plugin/localizedFormat';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import clsx from 'clsx';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import { ExistingDataContextProvider } from '@gitroom/frontend/components/launches/helpers/use.existing.data';
@ -215,7 +215,8 @@ export const WeekView = () => {
<div
className={clsx(
'text-[14px] font-[600] flex items-center justify-center gap-[6px]',
day.day === newDayjs().format('L') && 'text-newTableTextFocused'
day.day === newDayjs().format('L') &&
'text-newTableTextFocused'
)}
>
{day.day === newDayjs().format('L') && (
@ -391,7 +392,9 @@ export const CalendarColumn: FC<{
const isBeforeNow = useMemo(() => {
const originalUtc = getDate.startOf('hour');
return originalUtc.startOf('hour').isBefore(newDayjs().startOf('hour').utc());
return originalUtc
.startOf('hour')
.isBefore(newDayjs().startOf('hour').utc());
}, [getDate, num]);
const { start, stop } = useInterval(
@ -462,8 +465,10 @@ export const CalendarColumn: FC<{
: Fragment;
modal.openModal({
closeOnClickOutside: false,
removeLayout: true,
closeOnEscape: false,
withCloseButton: false,
askClose: true,
classNames: {
modal: 'w-[100%] max-w-[1400px] text-textColor',
},
@ -515,28 +520,24 @@ export const CalendarColumn: FC<{
? undefined
: await new Promise((resolve) => {
modal.openModal({
title: '',
title: t('select_set', 'Select a Set'),
closeOnClickOutside: true,
askClose: true,
closeOnEscape: true,
withCloseButton: false,
withCloseButton: true,
onClose: () => resolve('exit'),
classNames: {
modal: 'text-textColor',
},
children: (
<ModalWrapperComponent title={t('select_set', 'Select a Set')}>
<SetSelectionModal
sets={sets}
onSelect={(selectedSet) => {
resolve(selectedSet);
modal.closeAll();
}}
onContinueWithoutSet={() => {
resolve(undefined);
modal.closeAll();
}}
/>
</ModalWrapperComponent>
<SetSelectionModal
sets={sets}
onSelect={(selectedSet) => {
resolve(selectedSet);
modal.closeAll();
}}
onContinueWithoutSet={() => {
resolve(undefined);
modal.closeAll();
}}
/>
),
});
});
@ -547,6 +548,8 @@ export const CalendarColumn: FC<{
closeOnClickOutside: false,
closeOnEscape: false,
withCloseButton: false,
removeLayout: true,
askClose: true,
classNames: {
modal: 'w-[100%] max-w-[1400px] text-textColor',
},
@ -586,17 +589,14 @@ export const CalendarColumn: FC<{
const openStatistics = useCallback(
(id: string) => () => {
modal.openModal({
title: t('statistics', 'Statistics'),
closeOnClickOutside: true,
closeOnEscape: true,
withCloseButton: false,
classNames: {
modal: 'w-[100%] max-w-[1400px]',
},
children: (
<ModalWrapperComponent title={t('statistics', 'Statistics')}>
<StatisticsModal postId={id} />
</ModalWrapperComponent>
),
children: <StatisticsModal postId={id} />,
size: '80%',
// title: `Adding posts for ${getDate.format('DD/MM/YYYY HH:mm')}`,
});

View File

@ -1,7 +1,7 @@
import { FC, useCallback, useEffect, useState } from 'react';
import dayjs from 'dayjs';
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { Textarea } from '@gitroom/react/form/textarea';
import { Button } from '@gitroom/react/form/button';
import clsx from 'clsx';

View File

@ -1,6 +1,6 @@
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import React, { FC, useCallback, useEffect, useState } from 'react';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { Integration } from '@prisma/client';
import { Autocomplete } from '@mantine/core';
import useSWR from 'swr';

View File

@ -2,7 +2,7 @@ import React, { FC, useCallback, useMemo, useState } from 'react';
import { useUser } from '@gitroom/frontend/components/layout/user.context';
import { useRouter } from 'next/navigation';
import { deleteDialog } from '@gitroom/react/helpers/delete.dialog';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { FormProvider, SubmitHandler, useForm } from 'react-hook-form';
import { classValidatorResolver } from '@hookform/resolvers/class-validator';
import { GeneratorDto } from '@gitroom/nestjs-libraries/dtos/generator/generator.dto';
@ -153,6 +153,8 @@ const FirstStep: FC = (props) => {
closeOnClickOutside: false,
closeOnEscape: false,
withCloseButton: false,
removeLayout: true,
askClose: true,
classNames: {
modal: 'w-[100%] max-w-[1400px] bg-transparent text-textColor',
},
@ -301,7 +303,7 @@ export const GeneratorComponent = () => {
return;
}
modal.openModal({
title: '',
title: 'Generate Posts',
withCloseButton: false,
classNames: {
modal: 'bg-transparent text-textColor',
@ -309,9 +311,7 @@ export const GeneratorComponent = () => {
size: 'xl',
children: (
<CalendarWeekProvider {...all}>
<ModalWrapperComponent title="Generate Posts">
<GeneratorPopup />
</ModalWrapperComponent>
<GeneratorPopup />
</CalendarWeekProvider>
),
});

View File

@ -213,7 +213,9 @@ export const CreateThumbnail: FC<{
<div className="relative bg-black rounded-lg overflow-hidden">
<video
ref={videoRef}
src={backendUrl + '/public/stream?url=' + encodeURIComponent(media.path)}
src={
backendUrl + '/public/stream?url=' + encodeURIComponent(media.path)
}
className="w-full h-[200px] object-contain"
onLoadedMetadata={handleLoadedMetadata}
onTimeUpdate={handleTimeUpdate}
@ -360,163 +362,132 @@ export const MediaComponentInner: FC<{
}, [altText, newThumbnail, thumbnail, thumbnailTimestamp]);
return (
<div className="text-textColor fixed start-0 top-0 bg-primary/80 z-[300] w-full h-full p-[60px] animate-fade justify-center flex bg-black/40">
<div className="w-full h-full relative">
<div className="w-[500px] bg-sixth border-tableBorder border-2 rounded-xl pb-[20px] px-[20px] absolute left-[50%] top-[100px] -translate-x-[50%]">
<div className="flex">
<div className="flex-1">
<TopTitle title={'Media Setting'} />
</div>
<button
onClick={onClose}
className="outline-none absolute end-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root bg-primary 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>
<div className="mt-[10px] flex flex-col gap-[20px]">
<div className="flex flex-col space-y-2">
<label className="text-sm text-textColor font-medium">
Alt Text (for accessibility)
</label>
<input
type="text"
value={altText}
onChange={(e) => setAltText(e.target.value)}
placeholder="Describe the image/video content..."
className="w-full px-3 py-2 bg-fifth border border-tableBorder rounded-lg text-textColor placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-forth focus:border-transparent"
/>
</div>
{media?.path.indexOf('mp4') > -1 && (
<>
{/* Alt Text Input */}
<div>
{!isEditingThumbnail ? (
<div className="flex flex-col">
{/* Show existing thumbnail if it exists */}
{(newThumbnail || thumbnail) && (
<div className="flex flex-col space-y-2">
<span className="text-sm text-textColor">
Current Thumbnail:
</span>
<img
src={newThumbnail || thumbnail}
alt="Current thumbnail"
className="max-w-full max-h-[500px] object-contain rounded-lg border border-tableBorder"
/>
</div>
)}
<div className="mt-[10px] flex flex-col gap-[20px]">
<div className="flex flex-col space-y-2">
<label className="text-sm text-textColor font-medium">
Alt Text (for accessibility)
</label>
<input
type="text"
value={altText}
onChange={(e) => setAltText(e.target.value)}
placeholder="Describe the image/video content..."
className="w-full px-3 py-2 bg-fifth border border-tableBorder rounded-lg text-textColor placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-forth focus:border-transparent"
/>
</div>
{media?.path.indexOf('mp4') > -1 && (
<>
{/* Alt Text Input */}
<div>
{!isEditingThumbnail ? (
<div className="flex flex-col">
{/* Show existing thumbnail if it exists */}
{(newThumbnail || thumbnail) && (
<div className="flex flex-col space-y-2">
<span className="text-sm text-textColor">
Current Thumbnail:
</span>
<img
src={newThumbnail || thumbnail}
alt="Current thumbnail"
className="max-w-full max-h-[500px] object-contain rounded-lg border border-tableBorder"
/>
</div>
)}
{/* Action Buttons */}
<div className="flex space-x-2">
<button
disabled={loading}
onClick={() => setIsEditingThumbnail(true)}
className="bg-third text-textColor px-6 py-2 rounded-lg hover:bg-opacity-80 transition-all flex-1 border border-tableBorder"
>
{media.thumbnail || newThumbnail
? 'Edit Thumbnail'
: 'Create Thumbnail'}
</button>
{(thumbnail || newThumbnail) && (
<button
disabled={loading}
onClick={() => {
setNewThumbnail(null);
setThumbnail(null);
}}
className="bg-red-600 text-white px-6 py-2 rounded-lg hover:bg-opacity-80 transition-all flex-1 border border-red-700"
>
Clear Thumbnail
</button>
)}
</div>
</div>
) : (
<div>
{/* Back button */}
<div className="flex justify-start">
<button
onClick={() => setIsEditingThumbnail(false)}
className="text-textColor hover:text-white transition-colors flex items-center space-x-2"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19 12H5M12 19L5 12L12 5"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
<span>Back</span>
</button>
</div>
{/* Thumbnail Editor */}
<CreateThumbnail
onSelect={(blob: Blob, timestampMs: number) => {
// Convert blob to base64 or handle as needed
const reader = new FileReader();
reader.onload = () => {
// You can handle the result here - for now just call onSelect with the blob URL
const url = URL.createObjectURL(blob);
setNewThumbnail(url);
setThumbnailTimestamp(timestampMs);
setIsEditingThumbnail(false);
};
reader.readAsDataURL(blob);
}}
media={media}
altText={altText}
onAltTextChange={setAltText}
/>
</div>
{/* Action Buttons */}
<div className="flex space-x-2">
<button
disabled={loading}
onClick={() => setIsEditingThumbnail(true)}
className="bg-third text-textColor px-6 py-2 rounded-lg hover:bg-opacity-80 transition-all flex-1 border border-tableBorder"
>
{media.thumbnail || newThumbnail
? 'Edit Thumbnail'
: 'Create Thumbnail'}
</button>
{(thumbnail || newThumbnail) && (
<button
disabled={loading}
onClick={() => {
setNewThumbnail(null);
setThumbnail(null);
}}
className="bg-red-600 text-white px-6 py-2 rounded-lg hover:bg-opacity-80 transition-all flex-1 border border-red-700"
>
Clear Thumbnail
</button>
)}
</div>
</>
)}
</div>
) : (
<div>
{/* Back button */}
<div className="flex justify-start">
<button
onClick={() => setIsEditingThumbnail(false)}
className="text-textColor hover:text-white transition-colors flex items-center space-x-2"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19 12H5M12 19L5 12L12 5"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
<span>Back</span>
</button>
</div>
{!isEditingThumbnail && (
<div className="flex space-x-2 !mt-[20px]">
<button
disabled={loading}
onClick={onClose}
className="flex-1 bg-gray-600 text-white px-6 py-2 rounded-lg hover:bg-opacity-80 transition-all"
>
Cancel
</button>
<button
onClick={save}
className="flex-1 bg-forth text-white px-6 py-2 rounded-lg hover:bg-opacity-80 transition-all"
>
Save Changes
</button>
{/* Thumbnail Editor */}
<CreateThumbnail
onSelect={(blob: Blob, timestampMs: number) => {
// Convert blob to base64 or handle as needed
const reader = new FileReader();
reader.onload = () => {
// You can handle the result here - for now just call onSelect with the blob URL
const url = URL.createObjectURL(blob);
setNewThumbnail(url);
setThumbnailTimestamp(timestampMs);
setIsEditingThumbnail(false);
};
reader.readAsDataURL(blob);
}}
media={media}
altText={altText}
onAltTextChange={setAltText}
/>
</div>
)}
</div>
</>
)}
{!isEditingThumbnail && (
<div className="flex space-x-2 !mt-[20px]">
<button
disabled={loading}
onClick={onClose}
className="flex-1 bg-gray-600 text-white px-6 py-2 rounded-lg hover:bg-opacity-80 transition-all"
>
Cancel
</button>
<button
onClick={save}
className="flex-1 bg-forth text-white px-6 py-2 rounded-lg hover:bg-opacity-80 transition-all"
>
Save Changes
</button>
</div>
</div>
)}
</div>
);
};

View File

@ -11,7 +11,7 @@ import { useClickOutside } from '@mantine/hooks';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import { deleteDialog } from '@gitroom/react/helpers/delete.dialog';
import { useToaster } from '@gitroom/react/toaster/toaster';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { TimeTable } from '@gitroom/frontend/components/launches/time.table';
import {
Integrations,
@ -137,18 +137,12 @@ export const Menu: FC<{
(integration) => integration.id === id
);
modal.openModal({
classNames: {
modal: 'w-[100%] max-w-[600px] bg-transparent text-textColor',
},
size: '100%',
withCloseButton: false,
closeOnEscape: false,
closeOnClickOutside: false,
children: (
<ModalWrapperComponent title="Time Table Slots" ask={true}>
<TimeTable integration={findIntegration!} mutate={mutate} />
</ModalWrapperComponent>
),
askClose: true,
title: 'Time Table Slots',
children: <TimeTable integration={findIntegration!} mutate={mutate} />,
});
setShow(false);
}, [integrations]);
@ -175,6 +169,8 @@ export const Menu: FC<{
closeOnClickOutside: false,
closeOnEscape: false,
withCloseButton: false,
removeLayout: true,
askClose: true,
classNames: {
modal: 'w-[100%] max-w-[1400px] bg-transparent text-textColor',
},
@ -254,40 +250,36 @@ export const Menu: FC<{
classNames: {
modal: 'md',
},
title: '',
title: 'Move / Add to customer',
withCloseButton: false,
closeOnEscape: true,
closeOnClickOutside: true,
children: (
<ModalWrapperComponent title="Move / Add to customer">
<CustomerModal
// @ts-ignore
integration={findIntegration}
onClose={() => {
mutate();
toast.show('Customer Updated', 'success');
}}
/>
</ModalWrapperComponent>
<CustomerModal
// @ts-ignore
integration={findIntegration}
onClose={() => {
mutate();
toast.show('Customer Updated', 'success');
}}
/>
),
});
setShow(false);
}, [integrations]);
const updateCredentials = useCallback(() => {
modal.openModal({
title: '',
title: 'Custom URL',
withCloseButton: false,
classNames: {
modal: 'md',
},
children: (
<ModalWrapperComponent title="Custom URL">
<CustomVariables
identifier={findIntegration.identifier}
gotoUrl={(url: string) => router.push(url)}
variables={findIntegration.customFields}
/>
</ModalWrapperComponent>
<CustomVariables
identifier={findIntegration.identifier}
gotoUrl={(url: string) => router.push(url)}
variables={findIntegration.customFields}
/>
),
});
}, []);

View File

@ -1,5 +1,5 @@
import React, { useCallback } from 'react';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import dayjs from 'dayjs';
import { useCalendar } from '@gitroom/frontend/components/launches/calendar.context';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
@ -21,7 +21,7 @@ export const NewPost = () => {
? undefined
: await new Promise((resolve) => {
modal.openModal({
title: '',
title: t('select_set', 'Select a Set'),
closeOnClickOutside: true,
closeOnEscape: true,
withCloseButton: false,
@ -30,19 +30,17 @@ export const NewPost = () => {
modal: 'text-textColor',
},
children: (
<ModalWrapperComponent title={t('select_set', 'Select a Set')}>
<SetSelectionModal
sets={sets}
onSelect={(selectedSet) => {
resolve(selectedSet);
modal.closeAll();
}}
onContinueWithoutSet={() => {
resolve(undefined);
modal.closeAll();
}}
/>
</ModalWrapperComponent>
<SetSelectionModal
sets={sets}
onSelect={(selectedSet) => {
resolve(selectedSet);
modal.closeAll();
}}
onContinueWithoutSet={() => {
resolve(undefined);
modal.closeAll();
}}
/>
),
});
});
@ -53,6 +51,8 @@ export const NewPost = () => {
closeOnClickOutside: false,
closeOnEscape: false,
withCloseButton: false,
removeLayout: true,
askClose: true,
classNames: {
modal: 'w-[100%] max-w-[1400px] bg-transparent text-textColor',
},

View File

@ -56,10 +56,12 @@ const ActionControls = ({ store }: any) => {
body: formData,
})
).json();
close.setMedia([{
id: data.id,
path: data.path,
}]);
close.setMedia([
{
id: data.id,
path: data.path,
},
]);
close.close();
}}
>
@ -102,63 +104,34 @@ const Polonto: FC<{
};
}, []);
return (
<div className="fixed start-0 top-0 bg-primary/80 z-[300] w-full min-h-full px-[60px] animate-fade">
<div className="w-full h-full bg-sixth border-tableBorder border-2 rounded-xl pb-[20px] px-[20px] relative">
<div className="flex">
<div className="flex-1">
<TopTitle title="Design Media" />
</div>
<button
onClick={closeModal}
className="outline-none absolute end-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root bg-primary 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>
<div className="bg-white text-black relative z-[400] polonto">
<CloseContext.Provider
value={{
close: () => closeModal(),
setMedia,
}}
>
<PolotnoContainer
style={{
width: '100%',
height: '700px',
<div className="bg-white text-black relative z-[400] polonto">
<CloseContext.Provider
value={{
close: () => closeModal(),
setMedia,
}}
>
<PolotnoContainer
style={{
width: '100%',
height: '700px',
}}
>
<SidePanelWrap>
<SidePanel store={store} sections={features} />
</SidePanelWrap>
<WorkspaceWrap>
<Toolbar
store={store}
components={{
ActionControls,
}}
>
<SidePanelWrap>
<SidePanel store={store} sections={features} />
</SidePanelWrap>
<WorkspaceWrap>
<Toolbar
store={store}
components={{
ActionControls,
}}
/>
<Workspace store={store} />
<ZoomButtons store={store} />
</WorkspaceWrap>
</PolotnoContainer>
</CloseContext.Provider>
</div>
</div>
/>
<Workspace store={store} />
<ZoomButtons store={store} />
</WorkspaceWrap>
</PolotnoContainer>
</CloseContext.Provider>
</div>
);
};

View File

@ -1,6 +1,6 @@
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import React, { FC, useCallback, useState } from 'react';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { Integration } from '@prisma/client';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import { Button } from '@gitroom/react/form/button';

View File

@ -1,5 +1,5 @@
import React, { FC, Fragment, useCallback } from 'react';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import useSWR from 'swr';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import { useT } from '@gitroom/react/translation/get.transation.service.client';

View File

@ -10,7 +10,7 @@ import timezone from 'dayjs/plugin/timezone';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
// @ts-ignore
import useKeypress from 'react-use-keypress';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { sortBy } from 'lodash';
import { usePreventWindowUnload } from '@gitroom/react/helpers/use.prevent.window.unload';
import { useT } from '@gitroom/react/translation/get.transation.service.client';

View File

@ -5,7 +5,7 @@ import React, { FC, useMemo, useState, useCallback, useEffect } from 'react';
import { Web3ProviderInterface } from '@gitroom/frontend/components/launches/web3/web3.provider.interface';
import { useVariables } from '@gitroom/react/helpers/variable.context';
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { LoadingComponent } from '@gitroom/frontend/components/layout/loading';
import { ButtonCaster } from '@gitroom/frontend/components/auth/providers/farcaster.provider';
export const WrapcasterProvider: FC<Web3ProviderInterface> = (props) => {

View File

@ -4,7 +4,7 @@ import '@neynar/react/dist/style.css';
import React, { FC, useCallback, useEffect, useRef, useState } from 'react';
import { Web3ProviderInterface } from '@gitroom/frontend/components/launches/web3/web3.provider.interface';
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import { timer } from '@gitroom/helpers/utils/timer';
import { makeId } from '@gitroom/nestjs-libraries/services/make.is';

View File

@ -5,7 +5,7 @@ import React, { FC, useMemo, useState, useCallback, useEffect } from 'react';
import { Web3ProviderInterface } from '@gitroom/frontend/components/launches/web3/web3.provider.interface';
import { useVariables } from '@gitroom/react/helpers/variable.context';
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { LoadingComponent } from '@gitroom/frontend/components/layout/loading';
import {
NeynarAuthButton,

View File

@ -1,6 +1,6 @@
'use client';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import {
cookieName,
fallbackLng,
@ -70,7 +70,7 @@ export const ChangeLanguageComponent = () => {
const handleLanguageChange = (language: string) => {
setCookie(language);
i18next.changeLanguage(language);
modals.closeModal('change-language');
modals.closeCurrent();
};
// Function to get language name in its native script
@ -123,16 +123,9 @@ export const LanguageComponent = () => {
const t = useT();
const openModal = () => {
modal.openModal({
title: '',
withCloseButton: false,
modalId: 'change-language',
children: (
<ModalWrapperComponent title={t('change_language', 'Change Language')}>
<ChangeLanguageComponent />
</ModalWrapperComponent>
),
size: 'lg',
centered: true,
title: t('change_language', 'Change Language'),
withCloseButton: true,
children: <ChangeLanguageComponent />,
});
};
return (

View File

@ -72,6 +72,7 @@ export const LayoutSettings = ({ children }: { children: ReactNode }) => {
<CopilotKit
credentials="include"
runtimeUrl={backendUrl + '/copilot/chat'}
showDevConsole={false}
>
<MantineWrapper>
{user.tier === 'FREE' && searchParams.get('check') && (

View File

@ -0,0 +1,371 @@
import { create } from 'zustand';
import { makeId } from '@gitroom/nestjs-libraries/services/make.is';
import { useShallow } from 'zustand/react/shallow';
import React, {
createContext,
FC,
memo,
ReactNode,
useCallback,
useContext,
useEffect,
useMemo,
} from 'react';
import { Button } from '@gitroom/react/form/button';
import { useHotkeys } from 'react-hotkeys-hook';
import clsx from 'clsx';
import { EventEmitter } from 'events';
interface OpenModalInterface {
title?: string;
closeOnClickOutside?: boolean;
removeLayout?: boolean;
closeOnEscape?: boolean;
withCloseButton?: boolean;
askClose?: boolean;
onClose?: () => void;
children: ReactNode | ((close: () => void) => ReactNode);
classNames?: {
modal?: string;
};
size?: string | number;
height?: string | number;
id?: string;
}
interface ModalManagerStoreInterface {
closeById(id: string): void;
openModal(params: OpenModalInterface): void;
closeAll(): void;
}
interface State extends ModalManagerStoreInterface {
modalManager: Array<{ id: string } & OpenModalInterface>;
}
const useModalStore = create<State>((set) => ({
modalManager: [],
openModal: (params) =>
set((state) => ({
modalManager: [
...state.modalManager,
{ id: params.id || makeId(20), ...params },
],
})),
closeById: (id) =>
set((state) => ({
modalManager: state.modalManager.filter((modal) => modal.id !== id),
})),
closeAll: () => set({ modalManager: [] }),
}));
const CurrentModalContext = createContext({ id: '' });
interface ModalManagerInterface extends ModalManagerStoreInterface {
closeCurrent(): void;
}
export const useModals = () => {
const { closeAll, openModal, closeById } = useModalStore(
useShallow((state) => ({
openModal: state.openModal,
closeById: state.closeById,
closeAll: state.closeAll,
}))
);
const modalContext = useContext(CurrentModalContext);
return {
openModal,
closeAll,
closeById,
closeCurrent: () => {
if (modalContext.id) {
closeById(modalContext.id);
}
},
} satisfies ModalManagerInterface;
};
export const Component: FC<{
closeModal: (id: string) => void;
zIndex: number;
isLast: boolean;
modal: { id: string } & OpenModalInterface;
}> = memo(({ isLast, modal, closeModal, zIndex }) => {
const decision = useDecisionModal();
const closeModalFunction = useCallback(async () => {
if (modal.askClose) {
const open = await decision.open();
if (!open) {
return;
}
}
modal?.onClose?.();
closeModal(modal.id);
}, [modal.id, closeModal]);
const RenderComponent = useMemo(() => {
return typeof modal.children === 'function'
? modal.children(closeModalFunction)
: modal.children;
}, [modal, closeModalFunction]);
useHotkeys(
'Escape',
() => {
if (isLast) {
closeModalFunction();
}
},
[isLast, closeModalFunction]
);
if (modal.removeLayout) {
return (
<div
style={{ zIndex }}
className={clsx(
'fixed flex left-0 top-0 min-w-full min-h-full bg-popup transition-all animate-fadeIn overflow-y-auto pb-[50px] text-newTextColor',
!isLast && '!overflow-hidden'
)}
>
<div className="relative flex-1">
<div className="absolute top-0 left-0 min-w-full min-h-full">
<div
className="mx-auto py-[48px]"
{...(modal.size && { style: { width: modal.size } })}
>
{typeof modal.children === 'function'
? modal.children(closeModalFunction)
: modal.children}
</div>
</div>
</div>
</div>
);
}
return (
<CurrentModalContext.Provider value={{ id: modal.id }}>
<div
onClick={closeModalFunction}
style={{ zIndex }}
className="fixed flex left-0 top-0 min-w-full min-h-full bg-popup transition-all animate-fadeIn overflow-y-auto pb-[50px] text-newTextColor"
>
<div className="relative flex-1">
<div className="absolute top-0 left-0 min-w-full min-h-full pt-[100px] pb-[100px]">
<div
className={clsx(
!modal.removeLayout && 'gap-[40px] p-[32px]',
'bg-newBgColorInner mx-auto flex flex-col w-fit rounded-[24px] relative',
modal.size ? '' : 'min-w-[600px]'
)}
{...(modal.size && { style: { width: modal.size } })}
onClick={(e) => e.stopPropagation()}
>
<div className="flex items-center">
<div className="text-[24px] font-[600] flex-1">
{modal.title}
</div>
{typeof modal.withCloseButton === 'undefined' ||
modal.withCloseButton ? (
<div className="cursor-pointer">
<button
className="outline-none absolute end-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
type="button"
onClick={closeModalFunction}
>
<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>
) : null}
</div>
<div className="whitespace-pre-line">{RenderComponent}</div>
</div>
</div>
</div>
</div>
</CurrentModalContext.Provider>
);
});
export const ModalManagerInner: FC = () => {
const { closeModal, modalManager } = useModalStore(
useShallow((state) => ({
closeModal: state.closeById,
modalManager: state.modalManager,
}))
);
useEffect(() => {
if (modalManager.length > 0) {
document.querySelector('body')?.classList.add('overflow-hidden');
Array.from(document.querySelectorAll('.blurMe') || []).map((p) =>
p.classList.add('blur-xs', 'pointer-events-none')
);
} else {
document.querySelector('body')?.classList.remove('overflow-hidden');
Array.from(document.querySelectorAll('.blurMe') || []).map((p) =>
p.classList.remove('blur-xs', 'pointer-events-none')
);
}
}, [modalManager]);
if (modalManager.length === 0) {
return null;
}
return (
<>
<style>{`body, html { overflow: hidden !important; }`}</style>
{modalManager.map((modal, index) => (
<Component
isLast={modalManager.length - 1 === index}
key={modal.id}
modal={modal}
zIndex={200 + index}
closeModal={closeModal}
/>
))}
</>
);
};
export const ModalManager: FC<{ children: ReactNode }> = ({ children }) => {
return (
<div>
<ModalManagerEmitter />
<ModalManagerInner />
<div className="transition-all w-full">{children}</div>
</div>
);
};
const emitter = new EventEmitter();
export const showModalEmitter = (params: ModalManagerInterface) => {
emitter.emit('show', params);
};
export const ModalManagerEmitter: FC = () => {
const { showModal } = useModalStore(
useShallow((state) => ({
showModal: state.openModal,
}))
);
useEffect(() => {
emitter.on('show', (params: OpenModalInterface) => {
showModal(params);
});
return () => {
emitter.removeAllListeners('show');
};
}, []);
return null;
};
export const DecisionModal: FC<{
description: string;
approveLabel: string;
cancelLabel: string;
resolution: (value: boolean) => void;
}> = ({ description, cancelLabel, approveLabel, resolution }) => {
const { closeCurrent } = useModals();
return (
<div className="flex flex-col">
<div>{description}</div>
<div className="flex gap-[12px] mt-[16px]">
<Button
onClick={() => {
resolution(true);
closeCurrent();
}}
>
{approveLabel}
</Button>
<Button
onClick={() => {
resolution(false);
closeCurrent();
}}
>
{cancelLabel}
</Button>
</div>
</div>
);
};
export const decisionModalEmitter = new EventEmitter();
export const areYouSure = ({
title = 'Are you sure?',
description = 'Are you sure you want to close this modal?' as any,
approveLabel = 'Yes',
cancelLabel = 'No',
} = {}): Promise<boolean> => {
return new Promise<boolean>((newRes) => {
decisionModalEmitter.emit('open', {
title,
description,
approveLabel,
cancelLabel,
newRes,
});
});
};
export const DecisionEverywhere: FC = () => {
const decision = useDecisionModal();
useEffect(() => {
decisionModalEmitter.on('open', decision.open);
}, []);
return null;
};
export const useDecisionModal = () => {
const modals = useModals();
const open = useCallback(
({
title = 'Are you sure?',
description = 'Are you sure you want to close this modal?' as any,
approveLabel = 'Yes',
cancelLabel = 'No',
newRes = undefined as any,
} = {}) => {
return new Promise<boolean>((res) => {
modals.openModal({
title,
askClose: false,
onClose: () => res(false),
children: (
<DecisionModal
resolution={(value) => (newRes ? newRes(value) : res(value))}
description={description}
approveLabel={approveLabel}
cancelLabel={cancelLabel}
/>
),
});
});
},
[modals]
);
return { open };
};

View File

@ -1,19 +1,26 @@
import React, { FC, useEffect } from 'react';
import { useSearchParams } from 'next/navigation';
import { ModalWrapperComponent } from '@gitroom/frontend/components/new-launch/modal.wrapper.component';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { Button } from '@gitroom/react/form/button';
export const PreConditionComponentModal: FC = () => {
return (
<div className="flex flex-col gap-[16px]">
<div className="whitespace-pre-line">
This social channel was connected previously to another Postiz account.{'\n'}
To continue, please fast-track your trial for an immediate charge.{'\n'}{'\n'}
** Please be advised that the account will not eligible for a refund, and the charge is final.
This social channel was connected previously to another Postiz account.
{'\n'}
To continue, please fast-track your trial for an immediate charge.{'\n'}
{'\n'}
** Please be advised that the account will not eligible for a refund,
and the charge is final.
</div>
<div className="flex gap-[2px] justify-center">
<Button onClick={() => window.location.href='/billing?finishTrial=true'}>Fast track - Charge me now</Button>
<Button
onClick={() => (window.location.href = '/billing?finishTrial=true')}
>
Fast track - Charge me now
</Button>
<Button secondary={true}>Cancel</Button>
</div>
</div>
@ -25,17 +32,13 @@ export const PreConditionComponent: FC = () => {
useEffect(() => {
if (query.get('precondition')) {
modal.openModal({
title: '',
title: 'Suspicious activity detected',
withCloseButton: false,
classNames: {
modal: 'text-textColor',
},
size: 'auto',
children: (
<ModalWrapperComponent title="Suspicious activity detected">
<PreConditionComponentModal />
</ModalWrapperComponent>
),
children: <PreConditionComponentModal />,
});
}
}, []);

View File

@ -1,6 +1,6 @@
'use client';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import React, {
FC,
Ref,

View File

@ -128,39 +128,39 @@ export const useMenuItem = () => {
] satisfies MenuItemInterface[] as MenuItemInterface[];
const secondMenu = [
{
name: 'GrowChief',
icon: (
<svg
width="20"
height="21"
viewBox="0 0 50 28"
fill="none"
xmlns="http://www.w3.org/2000/svg"
data-tooltip-id="tooltip"
data-tooltip-content="New! Automate your X and LinkedIn outreach with GrowChief"
>
<path
d="M24.8789 0.191772C39.9967 0.198463 49.621 14.0845 49.6514 14.1283C49.6514 14.1283 40.0206 27.8931 24.8789 27.8998C9.73703 27.9062 0.189453 14.1283 0.189453 14.1283C0.235704 14.0609 9.77381 0.185332 24.8789 0.191772Z"
fill="none"
stroke="currentColor"
strokeWidth="3"
/>
<circle
cx="24.9189"
cy="14.2621"
r="9.1328"
fill="none"
stroke="currentColor"
strokeWidth="3"
/>
</svg>
),
path: 'https://growchief.com',
role: ['ADMIN', 'SUPERADMIN', 'USER'],
requireBilling: true,
},
// {
// name: 'GrowChief',
// icon: (
// <svg
// width="20"
// height="21"
// viewBox="0 0 50 28"
// fill="none"
// xmlns="http://www.w3.org/2000/svg"
// data-tooltip-id="tooltip"
// data-tooltip-content="New! Automate your X and LinkedIn outreach with GrowChief"
// >
// <path
// d="M24.8789 0.191772C39.9967 0.198463 49.621 14.0845 49.6514 14.1283C49.6514 14.1283 40.0206 27.8931 24.8789 27.8998C9.73703 27.9062 0.189453 14.1283 0.189453 14.1283C0.235704 14.0609 9.77381 0.185332 24.8789 0.191772Z"
// fill="none"
// stroke="currentColor"
// strokeWidth="3"
// />
//
// <circle
// cx="24.9189"
// cy="14.2621"
// r="9.1328"
// fill="none"
// stroke="currentColor"
// strokeWidth="3"
// />
// </svg>
// ),
// path: 'https://growchief.com',
// role: ['ADMIN', 'SUPERADMIN', 'USER'],
// requireBilling: true,
// },
{
name: t('affiliate', 'Affiliate'),
icon: (
@ -286,7 +286,7 @@ export const TopMenu: FC = () => {
const { isGeneral, billingEnabled } = useVariables();
return (
<>
<div className="flex flex-1 flex-col gap-[16px]">
<div className="flex flex-1 flex-col gap-[16px] blurMe">
{
// @ts-ignore
user?.orgId &&
@ -318,7 +318,7 @@ export const TopMenu: FC = () => {
))
}
</div>
<div className="flex flex-col gap-[16px]">
<div className="flex flex-col gap-[16px] blurMe">
{secondMenu
.filter((f) => {
if (f.hide) {

View File

@ -20,7 +20,7 @@ import {
import { capitalize, chunk, fill } from 'lodash';
import useSWR from 'swr';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import { Textarea } from '@gitroom/react/form/textarea';
import { FormProvider, SubmitHandler, useForm } from 'react-hook-form';

View File

@ -1,7 +1,7 @@
import React, { FC, useCallback, useContext, useMemo, useState } from 'react';
import { MarketplaceProvider } from '@gitroom/frontend/components/marketplace/marketplace.provider';
import { useUser } from '@gitroom/frontend/components/layout/user.context';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import { Input } from '@gitroom/react/form/input';
import { CustomSelect } from '@gitroom/react/form/custom.select';

View File

@ -10,7 +10,7 @@ import useSWR from 'swr';
import { Input } from '@gitroom/react/form/input';
import { useDebouncedCallback } from 'use-debounce';
import { OrderList } from '@gitroom/frontend/components/marketplace/order.list';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { Select } from '@gitroom/react/form/select';
import { countries } from '@gitroom/nestjs-libraries/services/stripe.country.list';
import { useT } from '@gitroom/react/translation/get.transation.service.client';

View File

@ -9,7 +9,7 @@ import useSWR from 'swr';
import { capitalize } from 'lodash';
import removeMd from 'remove-markdown';
import { deleteDialog } from '@gitroom/react/helpers/delete.dialog';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { Post as PrismaPost } from '@prisma/client';
import dynamic from 'next/dynamic';
import { IntegrationContext } from '@gitroom/frontend/components/launches/helpers/use.integration';

View File

@ -30,9 +30,13 @@ import { deleteDialog } from '@gitroom/react/helpers/delete.dialog';
import { useT } from '@gitroom/react/translation/get.transation.service.client';
import { ThirdPartyMedia } from '@gitroom/frontend/components/third-parties/third-party.media';
import { ReactSortable } from 'react-sortablejs';
import { useMediaSettings } from '@gitroom/frontend/components/launches/helpers/media.settings.component';
import {
MediaComponentInner,
useMediaSettings,
} from '@gitroom/frontend/components/launches/helpers/media.settings.component';
import { useLaunchStore } from '@gitroom/frontend/components/new-launch/store';
import { AiVideo } from '@gitroom/frontend/components/launches/ai.video';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
const Polonto = dynamic(
() => import('@gitroom/frontend/components/launches/polonto')
);
@ -246,7 +250,7 @@ export const MediaBox: FC<{
const dragAndDrop = useCallback(
async (event: ClipboardEvent<HTMLDivElement> | File[]) => {
if (!ref?.current?.setOptions) {
return ;
return;
}
// @ts-ignore
@ -564,12 +568,12 @@ export const MultiMediaComponent: FC<{
dummy,
} = props;
const user = useUser();
const modals = useModals();
useEffect(() => {
if (value) {
setCurrentMedia(value);
}
}, [value]);
const [modal, setShowModal] = useState(false);
const [mediaModal, setMediaModal] = useState(false);
const [currentMedia, setCurrentMedia] = useState(value);
const mediaDirectory = useMediaDirectory();
@ -598,17 +602,14 @@ export const MultiMediaComponent: FC<{
[currentMedia]
);
const showModal = useCallback(() => {
if (!modal) {
onOpen?.();
} else {
onClose?.();
}
setShowModal(!modal);
}, [modal, onOpen, onClose]);
const closeDesignModal = useCallback(() => {
onClose?.();
setMediaModal(false);
}, [modal]);
modals.openModal({
askClose: false,
children: (close) => (
<MediaBox setMedia={changeMedia} closeModal={close} />
),
});
}, [changeMedia]);
const clearMedia = useCallback(
(topIndex: number) => () => {
const newMedia = currentMedia?.filter((f, index) => index !== topIndex);
@ -622,10 +623,19 @@ export const MultiMediaComponent: FC<{
},
[currentMedia]
);
const designMedia = useCallback(() => {
onOpen?.();
setMediaModal(true);
}, []);
if (!!user?.tier?.ai && !dummy) {
modals.openModal({
askClose: false,
title: 'Design Media',
size: '80%',
children: (close) => (
<Polonto setMedia={changeMedia} closeModal={close} />
),
});
}
}, [changeMedia]);
const mediaSettings = useMediaSettings();
@ -634,11 +644,6 @@ export const MultiMediaComponent: FC<{
return (
<>
<div className="flex flex-col gap-[8px] bg-bigStrip rounded-bl-[8px] select-none w-full">
{modal && <MediaBox setMedia={changeMedia} closeModal={showModal} />}
{mediaModal && !!user?.tier?.ai && !dummy && (
<Polonto setMedia={changeMedia} closeModal={closeDesignModal} />
)}
<div className="flex gap-[10px]">
<Button
onClick={showModal}
@ -687,17 +692,31 @@ export const MultiMediaComponent: FC<{
<div className="w-full h-full relative group">
<div
onClick={async () => {
const data: any = await mediaSettings(media);
console.log(
value?.map((p) => (p.id === data.id ? data : p))
);
onChange({
target: {
name: 'upload',
value: value?.map((p) =>
p.id === data.id ? data : p
),
},
modals.openModal({
title: 'Media Settings',
children: (close) => (
<MediaComponentInner
media={media as any}
onClose={close}
onSelect={(value: any) => {
console.log(value);
onChange({
target: {
name: 'upload',
value: currentMedia.map((p) => {
if (p.id === media.id) {
return {
...p,
...value,
};
}
return p;
}),
},
});
}}
/>
),
});
}}
className="absolute top-[50%] left-[50%] -translate-x-[50%] -translate-y-[50%] bg-black/80 rounded-[10px] opacity-0 group-hover:opacity-100 transition-opacity z-[100]"

View File

@ -1,5 +1,5 @@
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import React, { FC } from 'react';
import { Button } from '@gitroom/react/form/button';
import copy from 'copy-to-clipboard';

View File

@ -20,11 +20,8 @@ import { weightedLength } from '@gitroom/helpers/utils/count.length';
import { deleteDialog } from '@gitroom/react/helpers/delete.dialog';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import { makeId } from '@gitroom/nestjs-libraries/services/make.is';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { capitalize } from 'lodash';
import { usePreventWindowUnload } from '@gitroom/react/helpers/use.prevent.window.unload';
// @ts-ignore
import useKeypress from 'react-use-keypress';
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import { SelectCustomer } from '@gitroom/frontend/components/launches/select.customer';
import { CopilotPopup } from '@copilotkit/react-ui';
@ -46,7 +43,6 @@ export const ManageModal: FC<AddEditModalProps> = (props) => {
const [loading, setLoading] = useState(false);
const toaster = useToaster();
const modal = useModals();
usePreventWindowUnload(true);
const { addEditSets, mutate, customClose, dummy } = props;
@ -136,8 +132,6 @@ export const ManageModal: FC<AddEditModalProps> = (props) => {
[integrations]
);
useKeypress('Escape', askClose);
const schedule = useCallback(
(type: 'draft' | 'now' | 'schedule') => async () => {
setLoading(true);
@ -166,6 +160,7 @@ export const ManageModal: FC<AddEditModalProps> = (props) => {
return;
}
console.log(checkAllValid);
for (const item of checkAllValid) {
if (item.valid === false) {
toaster.show('Some fields are not valid', 'warning');
@ -312,7 +307,7 @@ export const ManageModal: FC<AddEditModalProps> = (props) => {
<>
<div
className={clsx(
'flex flex-col md:flex-row bg-newBgLineColor gap-[1px] rounded-[24px]'
'flex flex-col md:flex-row bg-newBgLineColor gap-[1px] rounded-[24px] trz'
)}
>
<div
@ -496,11 +491,10 @@ export const ManageModal: FC<AddEditModalProps> = (props) => {
<ShowAllProviders ref={ref} />
</div>
</div>
</div>
<CopilotPopup
hitEscapeToClose={false}
clickOutsideToClose={true}
instructions={`
<CopilotPopup
hitEscapeToClose={false}
clickOutsideToClose={true}
instructions={`
You are an assistant that help the user to schedule their social media posts,
Here are the things you can do:
- Add a new comment / post to the list of posts
@ -511,11 +505,12 @@ Here are the things you can do:
Post content can be added using the addPostContentFor{num} function.
After using the addPostFor{num} it will create a new addPostContentFor{num+ 1} function.
`}
labels={{
title: 'Your Assistant',
initial: 'Hi! 👋 How can I assist you today?',
}}
/>
labels={{
title: 'Your Assistant',
initial: 'Hi! 👋 How can I assist you today?',
}}
/>
</div>
</>
);
};

View File

@ -1,5 +1,5 @@
import { FC, ReactNode, useEffect, useRef } from 'react';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { deleteDialog } from '@gitroom/react/helpers/delete.dialog';
import { useT } from '@gitroom/react/translation/get.transation.service.client';

View File

@ -69,6 +69,7 @@ export const LayoutComponent = ({ children }: { children: ReactNode }) => {
<CopilotKit
credentials="include"
runtimeUrl={backendUrl + '/copilot/chat'}
showDevConsole={false}
>
<MantineWrapper>
{user.tier === 'FREE' && searchParams.get('check') && (
@ -103,7 +104,7 @@ export const LayoutComponent = ({ children }: { children: ReactNode }) => {
</div>
</div>
</div>
<div className="flex-1 bg-newBgLineColor rounded-[12px] overflow-hidden flex flex-col gap-[1px]">
<div className="flex-1 bg-newBgLineColor rounded-[12px] overflow-hidden flex flex-col gap-[1px] blurMe">
<div className="flex bg-newBgColorInner h-[80px] px-[20px] items-center">
<div className="text-[24px] font-[600] flex flex-1">
<Title />

View File

@ -2,7 +2,7 @@
import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { Button } from '@gitroom/react/form/button';
import { ConnectChannels } from '@gitroom/frontend/components/onboarding/connect.channels';
import { useVariables } from '@gitroom/react/helpers/variable.context';
@ -46,15 +46,11 @@ export const Onboarding: FC = () => {
}
modalOpen.current = true;
modal.openModal({
title: '',
title: t('onboarding', 'Onboarding'),
withCloseButton: false,
closeOnEscape: false,
size: '900px',
children: (
<ModalWrapperComponent title={t('onboarding', 'Onboarding')}>
<Welcome />
</ModalWrapperComponent>
),
children: <Welcome />,
});
}, [query]);
return null;

View File

@ -9,7 +9,7 @@ import { Button } from '@gitroom/react/form/button';
import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import useSWR, { mutate } from 'swr';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import {
FormProvider,
@ -243,18 +243,17 @@ export const Plug = () => {
mutate();
},
size: '500px',
title: `Auto Plug: ${p.title}`,
children: (
<ModalWrapperComponent title={`Auto Plug: ${p.title}`}>
<PlugPop
plug={p}
data={data}
settings={{
identifier: plug.identifier,
providerId: plug.providerId,
name: plug.name,
}}
/>
</ModalWrapperComponent>
<PlugPop
plug={p}
data={data}
settings={{
identifier: plug.identifier,
providerId: plug.providerId,
name: plug.name,
}}
/>
),
});
},

View File

@ -26,6 +26,7 @@ export const PreviewWrapper = ({ children }: { children: ReactNode }) => {
<CopilotKit
credentials="include"
runtimeUrl={backendUrl + '/copilot/chat'}
showDevConsole={false}
>
<MantineWrapper>
<Toaster />

View File

@ -6,15 +6,14 @@ import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import useSWR from 'swr';
import { useUser } from '@gitroom/frontend/components/layout/user.context';
import { Button } from '@gitroom/react/form/button';
import { useModals } from '@mantine/modals';
import { Input } from '@gitroom/react/form/input';
import { useToaster } from '@gitroom/react/toaster/toaster';
import clsx from 'clsx';
import { deleteDialog } from '@gitroom/react/helpers/delete.dialog';
import { useT } from '@gitroom/react/translation/get.transation.service.client';
import dayjs from 'dayjs';
import { AddEditModal } from '@gitroom/frontend/components/new-launch/add.edit.modal';
import { newDayjs } from '@gitroom/frontend/components/layout/set.timezone';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
const SaveSetModal: FC<{
postData: any;
@ -97,9 +96,8 @@ export const Sets: FC = () => {
closeOnClickOutside: false,
closeOnEscape: false,
withCloseButton: false,
classNames: {
modal: 'w-[100%] max-w-[1400px] bg-transparent text-textColor',
},
removeLayout: true,
askClose: true,
children: (
<AddEditModal
allIntegrations={integrations.map((p: any) => ({
@ -109,10 +107,6 @@ export const Sets: FC = () => {
addEditSets={(data) => {
modal.openModal({
title: 'Save as Set',
classNames: {
modal: 'bg-sixth text-textColor',
title: 'text-textColor',
},
children: (
<SaveSetModal
initialValue={params?.name || ''}
@ -137,7 +131,6 @@ export const Sets: FC = () => {
onCancel={() => modal.closeAll()}
/>
),
size: 'md',
});
}}
reopenModal={() => {}}
@ -146,7 +139,6 @@ export const Sets: FC = () => {
date={newDayjs()}
/>
),
size: '80%',
title: ``,
});
},

View File

@ -3,7 +3,7 @@ import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import useSWR from 'swr';
import { Button } from '@gitroom/react/form/button';
import clsx from 'clsx';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import { array, boolean, object, string } from 'yup';
import { FormProvider, useForm } from 'react-hook-form';
@ -27,11 +27,8 @@ export const SignaturesComponent: FC<{
const addSignature = useCallback(
(data?: any) => () => {
modal.openModal({
title: '',
withCloseButton: false,
classNames: {
modal: 'bg-transparent text-textColor',
},
title: data ? 'Edit Signature' : 'Add Signature',
withCloseButton: true,
children: <AddOrRemoveSignature data={data} reload={mutate} />,
});
},
@ -170,7 +167,7 @@ const AddOrRemoveSignature: FC<{
: 'Signature added successfully',
'success'
);
modal.closeModal(modal.modals[modal.modals.length - 1].id);
modal.closeCurrent();
reload();
},
[data, modal]
@ -181,14 +178,11 @@ const AddOrRemoveSignature: FC<{
return (
<FormProvider {...form}>
<form onSubmit={form.handleSubmit(callBack)}>
<div className="relative flex gap-[20px] flex-col flex-1 rounded-[4px] border border-customColor6 bg-sixth p-[16px] pt-0 w-[500px]">
<TopTitle title={data ? 'Edit Signature' : 'Add Signature'} />
<div className="relative flex gap-[20px] flex-col flex-1 rounded-[4px] pt-0">
<button
className="outline-none absolute end-[20px] top-[15px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
type="button"
onClick={() =>
modal.closeModal(modal.modals[modal.modals.length - 1].id)
}
onClick={() => modal.closeCurrent()}
>
<svg
viewBox="0 0 15 15"

View File

@ -4,7 +4,7 @@ import useSWR from 'swr';
import React, { useCallback, useMemo } from 'react';
import { useUser } from '@gitroom/frontend/components/layout/user.context';
import { capitalize } from 'lodash';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import { Input } from '@gitroom/react/form/input';
import { useForm, FormProvider, useWatch } from 'react-hook-form';
@ -65,38 +65,13 @@ export const AddMember = () => {
},
[]
);
const closeModal = useCallback(() => {
return modals.closeAll();
}, []);
const t = useT();
return (
<FormProvider {...form}>
<form onSubmit={form.handleSubmit(submit)}>
<div className="relative flex gap-[10px] flex-col flex-1 rounded-[4px] border border-customColor6 bg-sixth p-[16px] pt-0">
<TopTitle title="Add Member" />
<button
onClick={closeModal}
className="outline-none absolute end-[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="relative flex gap-[10px] flex-col flex-1 p-[16px] pt-0">
{sendEmail && (
<Input
label="Email"
@ -153,7 +128,8 @@ export const TeamsComponent = () => {
classNames: {
modal: 'bg-transparent text-textColor',
},
withCloseButton: false,
title: 'Add Team Member',
withCloseButton: true,
children: <AddMember />,
});
}, []);

View File

@ -1,27 +1,26 @@
import { FC, useCallback, useState } from 'react';
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import { FC, useCallback } from 'react';
import { SignaturesComponent } from '@gitroom/frontend/components/settings/signatures.component';
import { Transforms } from 'slate';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
export const SignatureBox: FC<{
editor: any;
}> = ({ editor }) => {
const [showModal, setShowModal] = useState<any>(false);
const addSignature = useCallback(() => {
setShowModal(true);
}, [showModal]);
const modals = useModals();
const appendValue = (val: string) => {
editor?.commands?.insertContent("\n\n" + val);
editor?.commands?.insertContent('\n\n' + val);
editor?.commands?.focus();
setShowModal(false);
};
const addSignature = useCallback(() => {
modals.openModal({
title: 'Add Signature',
children: (close) => (
<SignatureModal appendSignature={appendValue} close={close} />
),
});
}, [appendValue]);
return (
<>
{showModal && (
<SignatureModal
appendSignature={appendValue}
close={() => setShowModal(false)}
/>
)}
<div
onClick={addSignature}
className="select-none cursor-pointer w-[40px] p-[5px] text-center"
@ -45,32 +44,10 @@ export const SignatureModal: FC<{
close: () => void;
appendSignature: (sign: string) => void;
}> = (props) => {
const { close, appendSignature } = props;
const { appendSignature } = props;
return (
<div className="bg-black/40 fixed start-0 top-0 w-full h-full z-[500]">
<div className="relative w-[900px] mx-auto flex gap-[20px] flex-col flex-1 rounded-[4px] border border-customColor6 bg-sixth p-[16px] pt-0">
<TopTitle title={`Add signature`} />
<button
className="outline-none absolute end-[20px] top-[15px] 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"
onClick={close}
>
<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="relative w-[900px] mx-auto flex gap-[20px] flex-col flex-1 rounded-[4px] pt-0">
<SignaturesComponent appendSignature={appendSignature} />
</div>
</div>

View File

@ -5,7 +5,7 @@ import useSWR from 'swr';
import React, { FC, useCallback, useState } from 'react';
import { Button } from '@gitroom/react/form/button';
import { useRouter } from 'next/navigation';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { FieldValues, FormProvider, useForm } from 'react-hook-form';
import { useT } from '@gitroom/react/translation/get.transation.service.client';
import { Input } from '@gitroom/react/form/input';
@ -115,12 +115,10 @@ export const ThirdPartyListComponent: FC<{ reload: () => void }> = (props) => {
const addApiKey = useCallback(
(title: string, identifier: string) => () => {
modals.openModal({
title: '',
title: `Add API key for ${title}`,
withCloseButton: false,
children: (
<ModalWrapperComponent title={`Add API key for ${title}`}>
<ApiModal identifier={identifier} title={title} update={reload} />
</ModalWrapperComponent>
<ApiModal identifier={identifier} title={title} update={reload} />
),
});
},

View File

@ -18,6 +18,7 @@ import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.titl
import './providers/heygen.provider';
import { thirdPartyList } from '@gitroom/frontend/components/third-parties/third-party.wrapper';
import { useLaunchStore } from '@gitroom/frontend/components/new-launch/store';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
const ThirdPartyContext = createContext({
id: '',
@ -92,93 +93,53 @@ export const ThirdPartyPopup: FC<{
}, []);
return (
<div
className="removeEditor fixed start-0 top-0 bg-primary/80 z-[300] w-full min-h-full animate-fade bg-black/30 rounded-[24px]"
onClick={closeModal}
>
<div className="relative">
<div className="absolute -top-[50px] left-0" ref={refNew} />
</div>
<div
className="max-w-[1000px] w-full h-full bg-sixth border-tableBorder border-2 rounded-xl relative mx-auto"
onClick={(e) => e.stopPropagation()}
>
<div className="pb-[20px] px-[20px] w-full h-full">
<div className="flex flex-col">
<div className="flex-1">
<TopTitle title="Integrations" />
</div>
<button
onClick={closeModal}
className="outline-none z-[300] absolute end-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root bg-primary hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
type="button"
<div className={clsx('flex flex-wrap flex-col gap-[10px] pt-[20px]')}>
{!thirdParty && (
<div className="grid grid-cols-4 gap-[10px] justify-items-center justify-center">
{thirdParties.map((p: any) => (
<div
onClick={() => {
setThirdParty(p);
}}
key={p.identifier}
className="w-full h-full p-[20px] min-h-[100px] text-[14px] bg-third hover:bg-input transition-all text-textColor relative flex flex-col gap-[15px] cursor-pointer"
>
<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>
<div className={clsx('flex flex-wrap flex-col gap-[10px] pt-[20px]')}>
{!thirdParty && (
<div className="grid grid-cols-4 gap-[10px] justify-items-center justify-center">
{thirdParties.map((p: any) => (
<div
onClick={() => {
setThirdParty(p);
}}
key={p.identifier}
className="w-full h-full p-[20px] min-h-[100px] text-[14px] bg-third hover:bg-input transition-all text-textColor relative flex flex-col gap-[15px] cursor-pointer"
>
<div>
<img
className="w-[32px] h-[32px]"
src={`/icons/third-party/${p.identifier}.png`}
/>
</div>
<div className="whitespace-pre-wrap text-left text-lg">
{p.title}: {p.name}
</div>
<div className="whitespace-pre-wrap text-left">
{p.description}
</div>
<div className="w-full flex">
<Button className="w-full">Use</Button>
</div>
</div>
))}
<div>
<img
className="w-[32px] h-[32px]"
src={`/icons/third-party/${p.identifier}.png`}
/>
</div>
)}
{thirdParty && (
<>
<div>
<div
className="cursor-pointer float-left"
onClick={() => setThirdParty(null)}
>
{'<'} Back
</div>
</div>
<ThirdPartyContext.Provider
value={{ ...thirdParty, data: allData, close, onChange }}
>
<Component />
</ThirdPartyContext.Provider>
</>
)}
</div>
<div className="whitespace-pre-wrap text-left text-lg">
{p.title}: {p.name}
</div>
<div className="whitespace-pre-wrap text-left">
{p.description}
</div>
<div className="w-full flex">
<Button className="w-full">Use</Button>
</div>
</div>
))}
</div>
</div>
)}
{thirdParty && (
<>
<div>
<div
className="cursor-pointer float-left"
onClick={() => setThirdParty(null)}
>
{'<'} Back
</div>
</div>
<ThirdPartyContext.Provider
value={{ ...thirdParty, data: allData, close, onChange }}
>
<Component />
</ThirdPartyContext.Provider>
</>
)}
</div>
);
};
@ -197,7 +158,7 @@ export const ThirdPartyMedia: FC<{
const { allData, onChange } = props;
const t = useT();
const fetch = useFetch();
const [popup, setPopup] = useState(false);
const modals = useModals();
const thirdParties = useCallback(async () => {
return (await (await fetch('/third-party')).json()).filter(
@ -220,20 +181,25 @@ export const ThirdPartyMedia: FC<{
return (
<>
{popup && (
<ThirdPartyPopup
thirdParties={data}
closeModal={() => setPopup(false)}
allData={allData}
onChange={onChange}
/>
)}
<div className="relative group">
<Button
className={clsx(
'relative ms-[10px] !px-[10px] rounded-[4px] gap-[8px] !text-primary justify-center items-center flex border border-dashed border-newBgLineColor bg-newColColor'
)}
onClick={() => setPopup(true)}
onClick={() => {
modals.openModal({
title: t('integrations', 'Integrations'),
size: '80%',
children: (close) => (
<ThirdPartyPopup
thirdParties={data}
closeModal={close}
allData={allData}
onChange={onChange}
/>
),
});
}}
>
<div className={clsx('flex gap-[5px] items-center')}>
<div>

View File

@ -3,7 +3,7 @@ import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import useSWR from 'swr';
import { useUser } from '@gitroom/frontend/components/layout/user.context';
import { Button } from '@gitroom/react/form/button';
import { useModals } from '@mantine/modals';
import { useModals } from '@gitroom/frontend/components/layout/new-modal';
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import { Input } from '@gitroom/react/form/input';
import { FormProvider, useForm } from 'react-hook-form';
@ -27,11 +27,8 @@ export const Webhooks: FC = () => {
const addWebhook = useCallback(
(data?: any) => () => {
modal.openModal({
title: '',
withCloseButton: false,
classNames: {
modal: 'bg-transparent text-textColor',
},
title: data ? 'Update webhook' : 'Add webhook',
withCloseButton: true,
children: <AddOrEditWebhook data={data} reload={mutate} />,
});
},
@ -246,29 +243,7 @@ export const AddOrEditWebhook: FC<{
return (
<FormProvider {...form}>
<form onSubmit={form.handleSubmit(callBack)}>
<div className="relative flex gap-[20px] flex-col flex-1 rounded-[4px] border border-customColor6 bg-sixth p-[16px] pt-0 w-[500px]">
<TopTitle title={data ? 'Edit webhook' : 'Add webhook'} />
<button
className="outline-none absolute end-[20px] top-[15px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
type="button"
onClick={modal.closeAll}
>
<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="relative flex gap-[20px] flex-col flex-1 rounded-[4px] pt-0">
<div>
<Input
label="Name"

View File

@ -73,8 +73,6 @@ module.exports = {
customColor55: 'var(--color-custom55)',
modalCustom: 'var(--color-modalCustom)',
newBgColor: 'var(--new-bgColor)',
newBgColorInner: 'var(--new-bgColorInner)',
newBgLineColor: 'var(--new-bgLineColor)',
@ -96,6 +94,7 @@ module.exports = {
menuDots: 'var(--new-menu-dots)',
menuDotsHover: 'var(--new-menu-hover)',
bigStrip: 'var(--new-big-strips)',
popup: 'var(--popup-color)',
},
gridTemplateColumns: {
13: 'repeat(13, minmax(0, 1fr));',
@ -110,6 +109,7 @@ module.exports = {
animation: {
fade: 'fadeOut 0.5s ease-in-out',
normalFadeIn: 'normalFadeIn 0.5s ease-in-out',
fadeIn: 'normalFadeIn 0.2s ease-in-out forwards',
normalFadeOut: 'normalFadeOut 0.5s linear 5s forwards',
overflow: 'overFlow 0.5s ease-in-out forwards',
overflowReverse: 'overFlowReverse 0.5s ease-in-out forwards',
@ -121,7 +121,7 @@ module.exports = {
yellow: '0 0 60px 20px #6b6237',
yellowToast: '0px 0px 50px rgba(252, 186, 3, 0.3)',
greenToast: '0px 0px 50px rgba(60, 124, 90, 0.3)',
menu: 'var(--menu-shadow)'
menu: 'var(--menu-shadow)',
},
// that is actual animation
keyframes: (theme) => ({

View File

@ -55,6 +55,7 @@ export class RedditSettingsDtoInner {
@ValidateIf((e) => e.is_flair_required)
@IsDefined()
@ValidateNested()
@Type(() => RedditFlairDto)
flair: RedditFlairDto;
}

View File

@ -50,7 +50,7 @@ export const Checkbox = forwardRef<
{...disableForm ? {} : form.register(props.name!)}
onClick={changeStatus}
className={clsx(
'cursor-pointer rounded-[4px] select-none w-[24px] h-[24px] justify-center items-center flex',
'cursor-pointer rounded-[4px] select-none w-[24px] h-[24px] justify-center items-center flex text-white',
variant === 'default' || !variant
? 'bg-forth'
: 'border-customColor1 border-2 bg-customColor2',

View File

@ -1,5 +1,5 @@
import Swal from 'sweetalert2';
import i18next from '@gitroom/react/translation/i18next';
import { areYouSure } from '@gitroom/frontend/components/layout/new-modal';
export const deleteDialog = async (
message: string,
@ -7,14 +7,11 @@ export const deleteDialog = async (
title?: string,
cancelButton?: string
) => {
const fire = await Swal.fire({
return areYouSure({
title: title || i18next.t('are_you_sure', 'Are you sure?'),
text: message,
icon: 'warning',
showCancelButton: true,
confirmButtonText:
description: message,
approveLabel:
confirmButton || i18next.t('yes_delete_it', 'Yes, delete it!'),
cancelButtonText: cancelButton || i18next.t('no_cancel', 'No, cancel!'),
cancelLabel: cancelButton || i18next.t('no_cancel', 'No, cancel!'),
});
return fire.isConfirmed;
};

View File

@ -1,26 +1,15 @@
'use client';
import { ReactNode } from 'react';
import { MantineProvider } from '@mantine/core';
import { ModalsProvider } from '@mantine/modals';
import i18next from '@gitroom/react/translation/i18next';
import {
DecisionEverywhere,
ModalManager,
} from '@gitroom/frontend/components/layout/new-modal';
export const MantineWrapper = (props: { children: ReactNode }) => {
const dir = i18next.dir();
return (
// @ts-ignore
<MantineProvider>
<ModalsProvider
modalProps={{
dir,
classNames: {
modal: 'bg-primary text-white',
close: 'bg-black hover:bg-black cursor-pointer',
},
}}
>
{props.children}
</ModalsProvider>
</MantineProvider>
<ModalManager>
<DecisionEverywhere />
{props.children}
</ModalManager>
);
};

View File

@ -186,6 +186,7 @@
"react-dom": "18.3.1",
"react-dropzone": "^14.3.5",
"react-hook-form": "^7.58.1",
"react-hotkeys-hook": "^5.1.0",
"react-i18next": "^15.5.2",
"react-loading": "^2.0.3",
"react-sortablejs": "^6.1.4",

View File

@ -57,7 +57,7 @@ importers:
'@mantine/hooks':
specifier: ^5.10.5
version: 5.10.5(react@18.3.1)
'@mantine/modals':
'@gitroom/frontend/components/layout/new-modal':
specifier: ^5.10.5
version: 5.10.5(@mantine/core@5.10.5(@emotion/react@11.14.0(@types/react@18.3.1)(react@18.3.1))(@mantine/hooks@5.10.5(react@18.3.1))(@types/react@18.3.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@5.10.5(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@modelcontextprotocol/sdk':
@ -438,6 +438,9 @@ importers:
react-hook-form:
specifier: ^7.58.1
version: 7.62.0(react@18.3.1)
react-hotkeys-hook:
specifier: ^5.1.0
version: 5.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react-i18next:
specifier: ^15.5.2
version: 15.7.3(i18next@25.5.2(typescript@5.5.4))(react-dom@18.3.1(react@18.3.1))(react-native@0.81.4(@babel/core@7.28.4)(@types/react@18.3.1)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(typescript@5.5.4)
@ -12884,6 +12887,12 @@ packages:
peerDependencies:
react: ^16.8.0 || ^17 || ^18 || ^19
react-hotkeys-hook@5.1.0:
resolution: {integrity: sha512-GCNGXjBzV9buOS3REoQFmSmE4WTvBhYQ0YrAeeMZI83bhXg3dRWsLHXDutcVDdEjwJqJCxk5iewWYX5LtFUd7g==}
peerDependencies:
react: '>=16.8.0'
react-dom: '>=16.8.0'
react-i18next@15.7.3:
resolution: {integrity: sha512-AANws4tOE+QSq/IeMF/ncoHlMNZaVLxpa5uUGW1wjike68elVYr0018L9xYoqBr1OFO7G7boDPrbn0HpMCJxTw==}
peerDependencies:
@ -31585,6 +31594,11 @@ snapshots:
dependencies:
react: 18.3.1
react-hotkeys-hook@5.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-i18next@15.7.3(i18next@25.5.2(typescript@5.5.4))(react-dom@18.3.1(react@18.3.1))(react-native@0.81.4(@babel/core@7.28.4)(@types/react@18.3.1)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(typescript@5.5.4):
dependencies:
'@babel/runtime': 7.28.4