feat: generate api modal

This commit is contained in:
Nevo David 2025-07-04 19:47:47 +07:00
parent 0f0bebeec9
commit 722460ce95
10 changed files with 246 additions and 115 deletions

View File

@ -0,0 +1,7 @@
export default async function LoginRequiredPage() {
return (
<div className="fixed left-0 top-0 w-full h-full bg-[#121212] z-[100] flex justify-center items-center text-4xl">
Login to use the wizard to generate API code
</div>
);
}

View File

@ -463,6 +463,7 @@ export const MediaBox: FC<{
export const MultiMediaComponent: FC<{
label: string;
description: string;
dummy: boolean;
allData: {
content: string;
id?: string;
@ -492,8 +493,17 @@ export const MultiMediaComponent: FC<{
};
}) => void;
}> = (props) => {
const { onOpen, onClose, name, error, text, onChange, value, allData } =
props;
const {
onOpen,
onClose,
name,
error,
text,
onChange,
value,
allData,
dummy,
} = props;
const user = useUser();
useEffect(() => {
if (value) {
@ -566,7 +576,7 @@ export const MultiMediaComponent: FC<{
<>
<div className="flex flex-col gap-[8px] bg-input rounded-bl-[8px] select-none w-full">
{modal && <MediaBox setMedia={changeMedia} closeModal={showModal} />}
{mediaModal && !!user?.tier?.ai && (
{mediaModal && !!user?.tier?.ai && !dummy && (
<Polonto setMedia={changeMedia} closeModal={closeDesignModal} />
)}
@ -668,40 +678,42 @@ export const MultiMediaComponent: FC<{
</ReactSortable>
)}
</div>
<div className="flex gap-[10px] bg-customColor55 w-full">
<div className="flex py-[10px]">
<Button
onClick={designMedia}
className="ms-[10px] rounded-[4px] gap-[8px] !text-primary justify-center items-center w-[127px] flex border border-dashed border-customColor21 bg-input"
>
<div className="flex gap-[5px] items-center">
<div>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M19.5 3H7.5C7.10218 3 6.72064 3.15804 6.43934 3.43934C6.15804 3.72064 6 4.10218 6 4.5V6H4.5C4.10218 6 3.72064 6.15804 3.43934 6.43934C3.15804 6.72064 3 7.10218 3 7.5V19.5C3 19.8978 3.15804 20.2794 3.43934 20.5607C3.72064 20.842 4.10218 21 4.5 21H16.5C16.8978 21 17.2794 20.842 17.5607 20.5607C17.842 20.2794 18 19.8978 18 19.5V18H19.5C19.8978 18 20.2794 17.842 20.5607 17.5607C20.842 17.2794 21 16.8978 21 16.5V4.5C21 4.10218 20.842 3.72064 20.5607 3.43934C20.2794 3.15804 19.8978 3 19.5 3ZM7.5 4.5H19.5V11.0044L17.9344 9.43875C17.6531 9.15766 17.2717 8.99976 16.8741 8.99976C16.4764 8.99976 16.095 9.15766 15.8137 9.43875L8.75344 16.5H7.5V4.5ZM16.5 19.5H4.5V7.5H6V16.5C6 16.8978 6.15804 17.2794 6.43934 17.5607C6.72064 17.842 7.10218 18 7.5 18H16.5V19.5ZM19.5 16.5H10.875L16.875 10.5L19.5 13.125V16.5ZM11.25 10.5C11.695 10.5 12.13 10.368 12.5 10.1208C12.87 9.87357 13.1584 9.52217 13.3287 9.11104C13.499 8.6999 13.5436 8.2475 13.4568 7.81105C13.37 7.37459 13.1557 6.97368 12.841 6.65901C12.5263 6.34434 12.1254 6.13005 11.689 6.04323C11.2525 5.95642 10.8001 6.00097 10.389 6.17127C9.97783 6.34157 9.62643 6.62996 9.37919 6.99997C9.13196 7.36998 9 7.80499 9 8.25C9 8.84674 9.23705 9.41903 9.65901 9.84099C10.081 10.2629 10.6533 10.5 11.25 10.5ZM11.25 7.5C11.3983 7.5 11.5433 7.54399 11.6667 7.6264C11.79 7.70881 11.8861 7.82594 11.9429 7.96299C11.9997 8.10003 12.0145 8.25083 11.9856 8.39632C11.9566 8.5418 11.8852 8.67544 11.7803 8.78033C11.6754 8.88522 11.5418 8.95665 11.3963 8.98559C11.2508 9.01453 11.1 8.99968 10.963 8.94291C10.8259 8.88614 10.7088 8.79001 10.6264 8.66668C10.544 8.54334 10.5 8.39834 10.5 8.25C10.5 8.05109 10.579 7.86032 10.7197 7.71967C10.8603 7.57902 11.0511 7.5 11.25 7.5Z"
fill="currentColor"
/>
</svg>
{!dummy && (
<div className="flex gap-[10px] bg-customColor55 w-full">
<div className="flex py-[10px]">
<Button
onClick={designMedia}
className="ms-[10px] rounded-[4px] gap-[8px] !text-primary justify-center items-center w-[127px] flex border border-dashed border-customColor21 bg-input"
>
<div className="flex gap-[5px] items-center">
<div>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M19.5 3H7.5C7.10218 3 6.72064 3.15804 6.43934 3.43934C6.15804 3.72064 6 4.10218 6 4.5V6H4.5C4.10218 6 3.72064 6.15804 3.43934 6.43934C3.15804 6.72064 3 7.10218 3 7.5V19.5C3 19.8978 3.15804 20.2794 3.43934 20.5607C3.72064 20.842 4.10218 21 4.5 21H16.5C16.8978 21 17.2794 20.842 17.5607 20.5607C17.842 20.2794 18 19.8978 18 19.5V18H19.5C19.8978 18 20.2794 17.842 20.5607 17.5607C20.842 17.2794 21 16.8978 21 16.5V4.5C21 4.10218 20.842 3.72064 20.5607 3.43934C20.2794 3.15804 19.8978 3 19.5 3ZM7.5 4.5H19.5V11.0044L17.9344 9.43875C17.6531 9.15766 17.2717 8.99976 16.8741 8.99976C16.4764 8.99976 16.095 9.15766 15.8137 9.43875L8.75344 16.5H7.5V4.5ZM16.5 19.5H4.5V7.5H6V16.5C6 16.8978 6.15804 17.2794 6.43934 17.5607C6.72064 17.842 7.10218 18 7.5 18H16.5V19.5ZM19.5 16.5H10.875L16.875 10.5L19.5 13.125V16.5ZM11.25 10.5C11.695 10.5 12.13 10.368 12.5 10.1208C12.87 9.87357 13.1584 9.52217 13.3287 9.11104C13.499 8.6999 13.5436 8.2475 13.4568 7.81105C13.37 7.37459 13.1557 6.97368 12.841 6.65901C12.5263 6.34434 12.1254 6.13005 11.689 6.04323C11.2525 5.95642 10.8001 6.00097 10.389 6.17127C9.97783 6.34157 9.62643 6.62996 9.37919 6.99997C9.13196 7.36998 9 7.80499 9 8.25C9 8.84674 9.23705 9.41903 9.65901 9.84099C10.081 10.2629 10.6533 10.5 11.25 10.5ZM11.25 7.5C11.3983 7.5 11.5433 7.54399 11.6667 7.6264C11.79 7.70881 11.8861 7.82594 11.9429 7.96299C11.9997 8.10003 12.0145 8.25083 11.9856 8.39632C11.9566 8.5418 11.8852 8.67544 11.7803 8.78033C11.6754 8.88522 11.5418 8.95665 11.3963 8.98559C11.2508 9.01453 11.1 8.99968 10.963 8.94291C10.8259 8.88614 10.7088 8.79001 10.6264 8.66668C10.544 8.54334 10.5 8.39834 10.5 8.25C10.5 8.05109 10.579 7.86032 10.7197 7.71967C10.8603 7.57902 11.0511 7.5 11.25 7.5Z"
fill="currentColor"
/>
</svg>
</div>
<div className="text-[12px] font-[500] !text-current">
{t('design_media', 'Design Media')}
</div>
</div>
<div className="text-[12px] font-[500] !text-current">
{t('design_media', 'Design Media')}
</div>
</div>
</Button>
</Button>
<ThirdPartyMedia allData={allData} onChange={changeMedia} />
<ThirdPartyMedia allData={allData} onChange={changeMedia} />
{!!user?.tier?.ai && (
<AiImage value={text} onChange={changeMedia} />
)}
{!!user?.tier?.ai && (
<AiImage value={text} onChange={changeMedia} />
)}
</div>
</div>
</div>
)}
</div>
<div className="text-[12px] text-red-400">{error}</div>
</>

View File

@ -11,6 +11,7 @@ import { useShallow } from 'zustand/react/shallow';
import { useExistingData } from '@gitroom/frontend/components/launches/helpers/use.existing.data';
export interface AddEditModalProps {
dummy?: boolean;
date: dayjs.Dayjs;
integrations: Integrations[];
allIntegrations?: Integrations[];
@ -33,16 +34,18 @@ export interface AddEditModalProps {
}
export const AddEditModal: FC<AddEditModalProps> = (props) => {
const { setAllIntegrations, setDate, setIsCreateSet } = useLaunchStore(
const { setAllIntegrations, setDate, setIsCreateSet, setDummy } = useLaunchStore(
useShallow((state) => ({
setAllIntegrations: state.setAllIntegrations,
setDate: state.setDate,
setIsCreateSet: state.setIsCreateSet,
setDummy: state.setDummy,
}))
);
const integrations = useLaunchStore((state) => state.integrations);
useEffect(() => {
setDummy(!!props.dummy);
setDate(props.date || dayjs());
setAllIntegrations(props.allIntegrations || []);
setIsCreateSet(!!props.addEditSets);

View File

@ -0,0 +1,48 @@
import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component';
import { useModals } from '@mantine/modals';
import React, { FC } from 'react';
import { Button } from '@gitroom/react/form/button';
import copy from 'copy-to-clipboard';
import { useToaster } from '@gitroom/react/toaster/toaster';
export const DummyCodeComponent: FC<{ code: any }> = ({ code }) => {
const modal = useModals();
const toaster = useToaster();
return (
<div className="rounded-[4px] border border-customColor6 bg-sixth px-[16px] pb-[16px] relative w-full">
<TopTitle title={`Output`}>
<Button
className="mr-[50px]"
onClick={() => {
copy(JSON.stringify(code, null, 2));
toaster.show('Code copied to clipboard', 'success');
}}
>
Copy Code
</Button>
</TopTitle>
<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={() => 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>
<pre>{JSON.stringify(code, null, 2)}</pre>
</div>
);
};

View File

@ -59,6 +59,7 @@ export const EditorWrapper: FC<{
internalFromAll,
totalChars,
postComment,
dummy,
} = useLaunchStore(
useShallow((state) => ({
internal: state.internal.find((p) => p.integration.id === state.current),
@ -66,6 +67,7 @@ export const EditorWrapper: FC<{
global: state.global,
current: state.current,
addRemoveInternal: state.addRemoveInternal,
dummy: state.dummy,
setInternalValueText: state.setInternalValueText,
setGlobalValueText: state.setGlobalValueText,
addInternalValue: state.addInternalValue,
@ -295,6 +297,7 @@ export const EditorWrapper: FC<{
identifier={internalFromAll?.identifier || 'global'}
totalChars={totalChars}
appendImages={appendImages(index)}
dummy={dummy}
/>
</div>
<div className="flex flex-col items-center gap-[10px]">
@ -373,6 +376,7 @@ export const Editor: FC<{
validateChars?: boolean;
identifier?: string;
totalChars?: number;
dummy: boolean;
}> = (props) => {
const {
allValues,
@ -383,6 +387,7 @@ export const Editor: FC<{
validateChars,
identifier,
appendImages,
dummy,
} = props;
const user = useUser();
const [id] = useState(makeId(10));
@ -536,6 +541,7 @@ export const Editor: FC<{
label={t('attachments', 'Attachments')}
description=""
value={props.pictures}
dummy={dummy}
name="image"
onChange={(value) => {
setImages(value.target.value);

View File

@ -28,6 +28,7 @@ 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';
import { DummyCodeComponent } from '@gitroom/frontend/components/new-launch/dummy.code.component';
function countCharacters(text: string, type: string): number {
if (type !== 'x') {
@ -46,7 +47,7 @@ export const ManageModal: FC<AddEditModalProps> = (props) => {
const modal = useModals();
usePreventWindowUnload(true);
const { addEditSets, mutate, customClose } = props;
const { addEditSets, mutate, customClose, dummy } = props;
const {
selectedIntegrations,
@ -98,7 +99,7 @@ export const ManageModal: FC<AddEditModalProps> = (props) => {
}, [existingData, mutate, modal]);
const askClose = useCallback(async () => {
if (!activateExitButton) {
if (!activateExitButton || dummy) {
return;
}
@ -117,7 +118,7 @@ export const ManageModal: FC<AddEditModalProps> = (props) => {
}
modal.closeAll();
}
}, [activateExitButton]);
}, [activateExitButton, dummy]);
const changeCustomer = useCallback(
(customer: string) => {
@ -212,16 +213,18 @@ export const ManageModal: FC<AddEditModalProps> = (props) => {
}
}
const shortLinkUrl = await (
await fetch('/posts/should-shortlink', {
method: 'POST',
body: JSON.stringify({
messages: checkAllValid.flatMap((p: any) =>
p.values.flatMap((a: any) => a.content)
),
}),
})
).json();
const shortLinkUrl = dummy
? { ask: false }
: await (
await fetch('/posts/should-shortlink', {
method: 'POST',
body: JSON.stringify({
messages: checkAllValid.flatMap((p: any) =>
p.values.flatMap((a: any) => a.content)
),
}),
})
).json();
const shortLink = !shortLinkUrl.ask
? false
@ -233,48 +236,68 @@ export const ManageModal: FC<AddEditModalProps> = (props) => {
const group = existingData.group || makeId(10);
const data = {
type,
inter: repeater || undefined,
...(repeater ? { inter: repeater } : {}),
tags,
shortLink,
date: date.utc().format('YYYY-MM-DDTHH:mm:ss'),
posts: checkAllValid.map((p: any) => ({
integration: p.integration,
posts: checkAllValid.map((post: any) => ({
integration: {
id: post.integration.id,
},
group,
settings: { ...(p.settings || {}) },
value: p.values.map((a: any) => ({
...a,
image: a.media || [],
content: a.content.slice(0, p.maximumCharacters || 1000000),
settings: { ...(post.settings || {}) },
value: post.values.map((value: any) => ({
...(value.id ? { id: value.id } : {}),
content: value.content.slice(0, post.maximumCharacters || 1000000),
image: value.media.map(({ id, path }: any) => ({ id, path })) || [],
})),
})),
};
addEditSets
? addEditSets(data)
: await fetch('/posts', {
method: 'POST',
body: JSON.stringify(data),
});
if (dummy) {
modal.openModal({
title: '',
children: <DummyCodeComponent code={data} />,
classNames: {
modal: 'w-[100%] bg-transparent text-textColor',
},
size: '100%',
withCloseButton: false,
closeOnEscape: true,
closeOnClickOutside: true,
});
if (!addEditSets) {
mutate();
toaster.show(
!existingData.integration
? 'Added successfully'
: 'Updated successfully'
);
}
if (customClose) {
setTimeout(() => {
customClose();
}, 2000);
setLoading(false);
}
if (!addEditSets) {
modal.closeAll();
if (!dummy) {
addEditSets
? addEditSets(data)
: await fetch('/posts', {
method: 'POST',
body: JSON.stringify(data),
});
if (!addEditSets) {
mutate();
toaster.show(
!existingData.integration
? 'Added successfully'
: 'Updated successfully'
);
}
if (customClose) {
setTimeout(() => {
customClose();
}, 2000);
}
if (!addEditSets) {
modal.closeAll();
}
}
},
[ref, repeater, tags, date, addEditSets]
[ref, repeater, tags, date, addEditSets, dummy]
);
return (
@ -292,13 +315,17 @@ export const ManageModal: FC<AddEditModalProps> = (props) => {
<div className="relative flex gap-[20px] flex-col flex-1 rounded-[4px] border border-customColor6 bg-sixth p-[16px] pt-0">
<TopTitle
title={
existingData.integration
dummy
? 'Generate an API request'
: existingData.integration
? t('update_post', 'Update Existing Post')
: t('create_new_post', 'Create Post')
}
>
<div className="flex items-center">
<RepeatComponent repeat={repeater} onChange={setRepeater} />
{!dummy && (
<RepeatComponent repeat={repeater} onChange={setRepeater} />
)}
<DatePicker onChange={setDate} date={date} />
</div>
</TopTitle>
@ -331,7 +358,7 @@ export const ManageModal: FC<AddEditModalProps> = (props) => {
</Button>
)}
{!addEditSets && (
{!addEditSets && !dummy && (
<Button
onClick={schedule('draft')}
className="rounded-[4px] border-2 border-customColor21"
@ -372,34 +399,38 @@ export const ManageModal: FC<AddEditModalProps> = (props) => {
'select_channels_from_circles',
'Select channels from the circles above'
)
: dummy
? 'Create output'
: !existingData?.integration
? t('add_to_calendar', 'Add to calendar')
: t('update', 'Update')}
</div>
<div className="h-full flex items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
>
<path
d="M15.0233 7.14804L9.39828 12.773C9.34604 12.8253 9.284 12.8668 9.21572 12.8951C9.14743 12.9234 9.07423 12.938 9.00031 12.938C8.92639 12.938 8.8532 12.9234 8.78491 12.8951C8.71662 12.8668 8.65458 12.8253 8.60234 12.773L2.97734 7.14804C2.8718 7.04249 2.8125 6.89934 2.8125 6.75007C2.8125 6.6008 2.8718 6.45765 2.97734 6.3521C3.08289 6.24655 3.22605 6.18726 3.37531 6.18726C3.52458 6.18726 3.66773 6.24655 3.77328 6.3521L9.00031 11.5798L14.2273 6.3521C14.2796 6.29984 14.3417 6.25838 14.4099 6.2301C14.4782 6.20181 14.5514 6.18726 14.6253 6.18726C14.6992 6.18726 14.7724 6.20181 14.8407 6.2301C14.909 6.25838 14.971 6.29984 15.0233 6.3521C15.0755 6.40436 15.117 6.46641 15.1453 6.53469C15.1736 6.60297 15.1881 6.67616 15.1881 6.75007C15.1881 6.82398 15.1736 6.89716 15.1453 6.96545C15.117 7.03373 15.0755 7.09578 15.0233 7.14804Z"
fill="white"
/>
</svg>
<div
onClick={schedule('now')}
className={clsx(
'hidden group-hover:flex hover:flex flex-col justify-center absolute start-0 top-[100%] w-full h-[40px] bg-customColor22 border border-tableBorder',
(locked || loading) &&
'cursor-not-allowed pointer-events-none opacity-50'
)}
>
{t('post_now', 'Post now')}
{!dummy && (
<div className="h-full flex items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
>
<path
d="M15.0233 7.14804L9.39828 12.773C9.34604 12.8253 9.284 12.8668 9.21572 12.8951C9.14743 12.9234 9.07423 12.938 9.00031 12.938C8.92639 12.938 8.8532 12.9234 8.78491 12.8951C8.71662 12.8668 8.65458 12.8253 8.60234 12.773L2.97734 7.14804C2.8718 7.04249 2.8125 6.89934 2.8125 6.75007C2.8125 6.6008 2.8718 6.45765 2.97734 6.3521C3.08289 6.24655 3.22605 6.18726 3.37531 6.18726C3.52458 6.18726 3.66773 6.24655 3.77328 6.3521L9.00031 11.5798L14.2273 6.3521C14.2796 6.29984 14.3417 6.25838 14.4099 6.2301C14.4782 6.20181 14.5514 6.18726 14.6253 6.18726C14.6992 6.18726 14.7724 6.20181 14.8407 6.2301C14.909 6.25838 14.971 6.29984 15.0233 6.3521C15.0755 6.40436 15.117 6.46641 15.1453 6.53469C15.1736 6.60297 15.1881 6.67616 15.1881 6.75007C15.1881 6.82398 15.1736 6.89716 15.1453 6.96545C15.117 7.03373 15.0755 7.09578 15.0233 7.14804Z"
fill="white"
/>
</svg>
<div
onClick={schedule('now')}
className={clsx(
'hidden group-hover:flex hover:flex flex-col justify-center absolute start-0 top-[100%] w-full h-[40px] bg-customColor22 border border-tableBorder',
(locked || loading) &&
'cursor-not-allowed pointer-events-none opacity-50'
)}
>
{t('post_now', 'Post now')}
</div>
</div>
</div>
)}
</div>
</Button>
)}
@ -417,17 +448,21 @@ export const ManageModal: FC<AddEditModalProps> = (props) => {
<TopTitle title="" removeTitle={true}>
<div className="flex flex-1 gap-[10px]">
<div>
<TagsComponent
name="tags"
label={t('tags', 'Tags')}
initial={tags}
onChange={(e) => setTags(e.target.value)}
/>
{!dummy && (
<TagsComponent
name="tags"
label={t('tags', 'Tags')}
initial={tags}
onChange={(e) => setTags(e.target.value)}
/>
)}
</div>
<SelectCustomer
onChange={changeCustomer}
integrations={integrations}
/>
{!dummy && (
<SelectCustomer
onChange={changeCustomer}
integrations={integrations}
/>
)}
</div>
<svg
onClick={askClose}

View File

@ -87,12 +87,14 @@ export const withProvider = function <T extends object>(params: {
justCurrent,
allIntegrations,
setPostComment,
dummy,
} = useLaunchStore(
useShallow((state) => ({
date: state.date,
tab: state.tab,
setTab: state.setTab,
global: state.global,
dummy: state.dummy,
internal: state.internal.find((p) => p.integration.id === props.id),
integrations: state.selectedIntegrations,
allIntegrations: state.integrations,
@ -304,7 +306,7 @@ export const withProvider = function <T extends object>(params: {
{(SettingsComponent || !!data?.internalPlugs?.length) && (
<div className={tab === 1 ? '' : 'hidden'}>
<SettingsComponent />
{!!data?.internalPlugs?.length && (
{!!data?.internalPlugs?.length && !dummy && (
<InternalChannels plugs={data?.internalPlugs} />
)}
</div>

View File

@ -27,6 +27,7 @@ interface SelectedIntegrations {
interface StoreState {
date: dayjs.Dayjs;
postComment: PostComment;
dummy: boolean;
repeater?: number;
isCreateSet: boolean;
totalChars: number;
@ -116,9 +117,11 @@ interface StoreState {
) => void;
setPostComment: (postComment: PostComment) => void;
setActivateExitButton?: (activateExitButton: boolean) => void;
setDummy: (dummy: boolean) => void;
}
const initialState = {
dummy: false,
activateExitButton: true,
date: dayjs(),
postComment: PostComment.ALL,
@ -505,4 +508,8 @@ export const useLaunchStore = create<StoreState>()((set) => ({
set((state) => ({
activateExitButton,
})),
setDummy: (dummy: boolean) =>
set((state) => ({
dummy,
})),
}));

View File

@ -5,17 +5,23 @@ import { FC, useCallback } from 'react';
import useSWR from 'swr';
import { useFetch } from '@gitroom/helpers/utils/custom.fetch';
import dayjs from 'dayjs';
import { usePathname } from 'next/navigation';
import { useParams } from 'next/navigation';
import { AddEditModal } from '@gitroom/frontend/components/new-launch/add.edit.modal';
export const StandaloneModal: FC = () => {
const fetch = useFetch();
const params = usePathname();
const params = useParams<{ platform: string }>();
const load = useCallback(async (path: string) => {
return (await (await fetch(path)).json()).integrations;
}, []);
const loadDate = useCallback(async () => {
if (params.platform === 'all') {
return dayjs().utc().format('YYYY-MM-DDTHH:mm:ss');
}
return (await (await fetch('/posts/find-slot')).json()).date;
}, []);
const {
isLoading,
data: integrations,
@ -31,6 +37,7 @@ export const StandaloneModal: FC = () => {
}
return (
<AddEditModal
dummy={params.platform === 'all'}
customClose={() => {
window.parent.postMessage(
{

View File

@ -31,6 +31,10 @@ export async function middleware(request: NextRequest) {
headers.set(headerName, lng);
}
if (nextUrl.pathname.startsWith('/modal/') && !authCookie) {
return NextResponse.redirect(new URL(`/auth/login-required`, nextUrl.href));
}
if (
nextUrl.pathname.startsWith('/uploads/') ||
nextUrl.pathname.startsWith('/p/') ||