feat: limit fields
This commit is contained in:
parent
c379247c28
commit
b195608f3b
|
|
@ -14,6 +14,9 @@ html {
|
|||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
#tooltip {
|
||||
z-index: 10000;
|
||||
}
|
||||
.box:after {
|
||||
border-radius: 50px;
|
||||
width: 100%;
|
||||
|
|
|
|||
|
|
@ -260,18 +260,36 @@ export const AddEditModal: FC<{
|
|||
group: existingData?.group,
|
||||
trigger: values[v].trigger,
|
||||
settings: values[v].settings(),
|
||||
checkValidity: values[v].checkValidity
|
||||
checkValidity: values[v].checkValidity,
|
||||
maximumCharacters: values[v].maximumCharacters,
|
||||
}));
|
||||
|
||||
for (const key of allKeys) {
|
||||
if (key.checkValidity) {
|
||||
const check = await key.checkValidity(key?.value.map((p: any) => p.image || []));
|
||||
const check = await key.checkValidity(
|
||||
key?.value.map((p: any) => p.image || [])
|
||||
);
|
||||
if (typeof check === 'string') {
|
||||
toaster.show(check, 'warning');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
key.value.some(
|
||||
(p) => p.content.length > (key.maximumCharacters || 1000000)
|
||||
)
|
||||
) {
|
||||
if (
|
||||
!(await deleteDialog(
|
||||
`${key?.integration?.name} post is too long, it will be cropped, do you want to continue?`
|
||||
))
|
||||
) {
|
||||
await key.trigger();
|
||||
moveToIntegration({identifier: key?.integration?.id!, toPreview: true});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (key.value.some((p) => !p.content || p.content.length < 6)) {
|
||||
setShowError(true);
|
||||
|
|
@ -280,7 +298,7 @@ export const AddEditModal: FC<{
|
|||
|
||||
if (!key.valid) {
|
||||
await key.trigger();
|
||||
moveToIntegration(key?.integration?.id!);
|
||||
moveToIntegration({identifier: key?.integration?.id!});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -305,7 +323,14 @@ export const AddEditModal: FC<{
|
|||
);
|
||||
modal.closeAll();
|
||||
},
|
||||
[postFor, dateState, value, integrations, existingData, selectedIntegrations]
|
||||
[
|
||||
postFor,
|
||||
dateState,
|
||||
value,
|
||||
integrations,
|
||||
existingData,
|
||||
selectedIntegrations,
|
||||
]
|
||||
);
|
||||
|
||||
const getPostsMarketplace = useCallback(async () => {
|
||||
|
|
@ -373,7 +398,7 @@ export const AddEditModal: FC<{
|
|||
|
||||
{!existingData.integration && (
|
||||
<PickPlatforms
|
||||
integrations={integrations.filter(f => !f.disabled)}
|
||||
integrations={integrations.filter((f) => !f.disabled)}
|
||||
selectedIntegrations={[]}
|
||||
singleSelect={false}
|
||||
onChange={setSelectedIntegrations}
|
||||
|
|
|
|||
|
|
@ -4,16 +4,17 @@ import { useFormatting } from '@gitroom/frontend/components/launches/helpers/use
|
|||
import clsx from 'clsx';
|
||||
import { VideoOrImage } from '@gitroom/react/helpers/video.or.image';
|
||||
import { Chakra_Petch } from 'next/font/google';
|
||||
import { FC } from 'react';
|
||||
const chakra = Chakra_Petch({ weight: '400', subsets: ['latin'] });
|
||||
|
||||
export const GeneralPreviewComponent = () => {
|
||||
export const GeneralPreviewComponent: FC<{maximumCharacters?: number}> = (props) => {
|
||||
const { value: topValue, integration } = useIntegration();
|
||||
const mediaDir = useMediaDirectory();
|
||||
const newValues = useFormatting(topValue, {
|
||||
removeMarkdown: true,
|
||||
saveBreaklines: true,
|
||||
specialFunc: (text: string) => {
|
||||
return text.slice(0, 280);
|
||||
return text.slice(0, props.maximumCharacters || 10000) + '<mark class="bg-red-500" data-tooltip-id="tooltip" data-tooltip-content="This text will be cropped">' + text?.slice(props.maximumCharacters || 10000) + '</mark>';
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -61,9 +62,7 @@ export const GeneralPreviewComponent = () => {
|
|||
@username
|
||||
</div>
|
||||
</div>
|
||||
<pre className={clsx('text-wrap', chakra.className)}>
|
||||
{value.text}
|
||||
</pre>
|
||||
<pre className={clsx('text-wrap', chakra.className)} dangerouslySetInnerHTML={{__html: value.text}} />
|
||||
{!!value?.images?.length && (
|
||||
<div className={clsx("w-full rounded-[16px] overflow-hidden mt-[12px]", value?.images?.length > 3 ? 'grid grid-cols-2 gap-[4px]' : 'flex gap-[4px]')}>
|
||||
{value.images.map((image, index) => (
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ export const PickPlatforms: FC<{
|
|||
useMoveToIntegrationListener(
|
||||
[integrations],
|
||||
props.singleSelect,
|
||||
(identifier) => {
|
||||
({identifier, toPreview}: {identifier: string, toPreview: boolean}) => {
|
||||
const findIntegration = integrations.find((p) => p.id === identifier);
|
||||
|
||||
if (findIntegration) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export const useFormatting = (
|
|||
params: {
|
||||
removeMarkdown?: boolean;
|
||||
saveBreaklines?: boolean;
|
||||
specialFunc?: (text: string) => string;
|
||||
specialFunc?: (text: string) => any;
|
||||
beforeSpecialFunc?: (text: string) => string;
|
||||
}
|
||||
) => {
|
||||
|
|
|
|||
|
|
@ -5,15 +5,15 @@ import { useCallback, useEffect } from 'react';
|
|||
|
||||
const emitter = new EventEmitter();
|
||||
export const useMoveToIntegration = () => {
|
||||
return useCallback((identifier: string) => {
|
||||
emitter.emit('moveToIntegration', identifier);
|
||||
return useCallback(({identifier, toPreview}: {identifier: string, toPreview?: boolean}) => {
|
||||
emitter.emit('moveToIntegration', {identifier, toPreview});
|
||||
}, []);
|
||||
};
|
||||
|
||||
export const useMoveToIntegrationListener = (
|
||||
useEffectParams: any[],
|
||||
enabled: boolean,
|
||||
callback: (identifier: string) => void
|
||||
callback: ({identifier, toPreview}: {identifier: string, toPreview: boolean}) => void
|
||||
) => {
|
||||
useEffect(() => {
|
||||
if (!enabled) {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ const finalInformation = {} as {
|
|||
trigger: () => Promise<boolean>;
|
||||
isValid: boolean;
|
||||
checkValidity?: (value: Array<Array<{path: string}>>) => Promise<string|true>;
|
||||
maximumCharacters?: number;
|
||||
};
|
||||
};
|
||||
export const useValues = (
|
||||
|
|
@ -18,6 +19,7 @@ export const useValues = (
|
|||
value: Array<{ id?: string; content: string; media?: Array<string> }>,
|
||||
dto: any,
|
||||
checkValidity?: (value: Array<Array<{path: string}>>) => Promise<string|true>,
|
||||
maximumCharacters?: number,
|
||||
) => {
|
||||
const resolver = useMemo(() => {
|
||||
return classValidatorResolver(dto);
|
||||
|
|
@ -45,6 +47,10 @@ export const useValues = (
|
|||
checkValidity;
|
||||
}
|
||||
|
||||
if (maximumCharacters) {
|
||||
finalInformation[integration].maximumCharacters = maximumCharacters;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
delete finalInformation[integration];
|
||||
|
|
|
|||
|
|
@ -129,4 +129,4 @@ const FacebookPreview: FC = (props) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default withProvider(null, FacebookPreview);
|
||||
export default withProvider(null, FacebookPreview, undefined, undefined, 63206);
|
||||
|
|
|
|||
|
|
@ -72,7 +72,8 @@ export const withProvider = (
|
|||
SettingsComponent: FC | null,
|
||||
PreviewComponent: FC,
|
||||
dto?: any,
|
||||
checkValidity?: (value: Array<Array<{path: string}>>) => Promise<string|true>
|
||||
checkValidity?: (value: Array<Array<{path: string}>>) => Promise<string|true>,
|
||||
maximumCharacters?: number
|
||||
) => {
|
||||
return (props: {
|
||||
identifier: string;
|
||||
|
|
@ -115,9 +116,9 @@ export const withProvider = (
|
|||
}, [SettingsComponent]);
|
||||
|
||||
// in case there is an error on submit, we change to the settings tab for the specific provider
|
||||
useMoveToIntegrationListener([props.id], true, (identifier) => {
|
||||
useMoveToIntegrationListener([props.id], true, ({identifier, toPreview}) => {
|
||||
if (identifier === props.id) {
|
||||
setShowTab(2);
|
||||
setShowTab(toPreview ? 1 : 2);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -128,7 +129,8 @@ export const withProvider = (
|
|||
props.identifier,
|
||||
editInPlace ? InPlaceValue : props.value,
|
||||
dto,
|
||||
checkValidity
|
||||
checkValidity,
|
||||
maximumCharacters
|
||||
);
|
||||
|
||||
// change editor value
|
||||
|
|
@ -398,7 +400,7 @@ export const withProvider = (
|
|||
{(editInPlace ? InPlaceValue : props.value)
|
||||
.map((p) => p.content)
|
||||
.join('').length ? (
|
||||
<GeneralPreviewComponent />
|
||||
<GeneralPreviewComponent maximumCharacters={maximumCharacters} />
|
||||
) : (
|
||||
<>No Content Yet</>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -138,5 +138,6 @@ export default withProvider(
|
|||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
},
|
||||
2200
|
||||
);
|
||||
|
|
|
|||
|
|
@ -129,4 +129,4 @@ const LinkedinPreview: FC = (props) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default withProvider(null, LinkedinPreview);
|
||||
export default withProvider(null, LinkedinPreview, undefined, undefined, 3000);
|
||||
|
|
|
|||
|
|
@ -203,5 +203,6 @@ export default withProvider(
|
|||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
},
|
||||
500
|
||||
);
|
||||
|
|
|
|||
|
|
@ -202,4 +202,4 @@ const RedditSettings: FC = () => {
|
|||
);
|
||||
};
|
||||
|
||||
export default withProvider(RedditSettings, RedditPreview, RedditSettingsDto);
|
||||
export default withProvider(RedditSettings, RedditPreview, RedditSettingsDto, undefined, 10000);
|
||||
|
|
|
|||
|
|
@ -134,5 +134,6 @@ export default withProvider(
|
|||
undefined,
|
||||
async ([firstPost, ...otherPosts]) => {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
500
|
||||
);
|
||||
|
|
|
|||
|
|
@ -276,5 +276,6 @@ export default withProvider(
|
|||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
},
|
||||
2200
|
||||
);
|
||||
|
|
|
|||
|
|
@ -102,4 +102,4 @@ const XPreview: FC = (props) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default withProvider(null, XPreview);
|
||||
export default withProvider(null, XPreview, undefined, undefined, 280);
|
||||
|
|
|
|||
|
|
@ -185,5 +185,6 @@ export default withProvider(
|
|||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
},
|
||||
5000
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue