feat: language
This commit is contained in:
parent
ac649424c6
commit
f460fdf252
|
|
@ -102,7 +102,7 @@ export const ActionComponent: FC<{
|
|||
|
||||
return (
|
||||
<div className="g-wrapper" style={{ position: 'relative' }}>
|
||||
<div className="absolute left-0 top-0 z-[9999] w-full h-full" />
|
||||
<div className="absolute start-0 top-0 z-[9999] w-full h-full" />
|
||||
{modal && (
|
||||
<Comp
|
||||
platform={provider.identifier}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export default async function Auth({
|
|||
const t = await getT();
|
||||
if (!post.length) {
|
||||
return (
|
||||
<div className="text-white fixed left-0 top-0 w-full h-full flex justify-center items-center text-[20px]">
|
||||
<div className="text-white fixed start-0 top-0 w-full h-full flex justify-center items-center text-[20px]">
|
||||
{t('post_not_found', 'Post not found')}
|
||||
</div>
|
||||
);
|
||||
|
|
@ -119,7 +119,7 @@ export default async function Auth({
|
|||
src={post[0].integration.picture}
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute -right-[5px] -bottom-[5px] w-[30px] h-[30px] z-[20]">
|
||||
<div className="absolute -end-[5px] -bottom-[5px] w-[30px] h-[30px] z-[20]">
|
||||
<img
|
||||
className="w-full h-full bg-black aspect-square rounded-full border-tableBorder"
|
||||
alt={post[0].integration.providerIdentifier}
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@ export default async function AuthLayout({
|
|||
return (
|
||||
<div className="dark !bg-black">
|
||||
<ReturnUrlComponent />
|
||||
<div className="absolute left-0 top-0 z-[0] h-[100vh] w-[100vw] overflow-hidden bg-loginBg bg-contain bg-no-repeat bg-left-top" />
|
||||
<div className="absolute start-0 top-0 z-[0] h-[100vh] w-[100vw] overflow-hidden bg-loginBg bg-contain bg-no-repeat bg-left-top" />
|
||||
<div className="relative z-[1] px-3 lg:pr-[100px] xs:mt-[70px] flex justify-center lg:justify-end items-center h-[100vh] w-[100vw] overflow-hidden">
|
||||
<div className="w-full max-w-lg h-[614px] flex flex-col bg-loginBox bg-no-repeat bg-contain">
|
||||
<div className="w-full relative">
|
||||
<div className="custom:fixed custom:text-left custom:left-[20px] custom:justify-start custom:top-[20px] absolute -top-[100px] text-textColor justify-center items-center w-full flex gap-[10px]">
|
||||
<div className="custom:fixed custom:text-start custom:left-[20px] custom:justify-start custom:top-[20px] absolute -top-[100px] text-textColor justify-center items-center w-full flex gap-[10px]">
|
||||
<Image
|
||||
src={isGeneralServerSide() ? '/postiz.svg' : '/logo.svg'}
|
||||
width={55}
|
||||
|
|
@ -72,11 +72,11 @@ export default async function AuthLayout({
|
|||
<div className="absolute top-0 bg-gradient-to-t from-customColor9 w-[1px] translate-x-[22px] h-full" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="absolute right-0 bg-gradient-to-l from-customColor9 h-[1px] translate-y-[60px] w-full" />
|
||||
<div className="absolute end-0 bg-gradient-to-l from-customColor9 h-[1px] translate-y-[60px] w-full" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute top-0 bg-gradient-to-t from-customColor9 w-[1px] -translate-x-[22px] h-full" />
|
||||
<div className="absolute right-0 bg-gradient-to-l from-customColor9 h-[1px] -translate-y-[22px] w-full" />
|
||||
<div className="absolute end-0 bg-gradient-to-l from-customColor9 h-[1px] -translate-y-[22px] w-full" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ import { ToltScript } from '@gitroom/frontend/components/layout/tolt.script';
|
|||
import { FacebookComponent } from '@gitroom/frontend/components/layout/facebook.component';
|
||||
import { headers } from 'next/headers';
|
||||
import { headerName } from '@gitroom/react/translation/i18n.config';
|
||||
import { HtmlComponent } from '@gitroom/frontend/components/layout/html.component';
|
||||
|
||||
const chakra = Chakra_Petch({
|
||||
weight: '400',
|
||||
subsets: ['latin'],
|
||||
|
|
@ -26,7 +28,7 @@ export default async function AppLayout({ children }: { children: ReactNode }) {
|
|||
? PlausibleProvider
|
||||
: Fragment;
|
||||
return (
|
||||
<html className={interClass}>
|
||||
<HtmlComponent className={interClass}>
|
||||
<head>
|
||||
<link rel="icon" href="/favicon.ico" sizes="any" />
|
||||
</head>
|
||||
|
|
@ -70,6 +72,6 @@ export default async function AppLayout({ children }: { children: ReactNode }) {
|
|||
</Plausible>
|
||||
</VariableContextComponent>
|
||||
</body>
|
||||
</html>
|
||||
</HtmlComponent>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -466,3 +466,7 @@ div div .set-font-family {
|
|||
.hideCopilot .copilotKitPopup {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
html[dir='rtl'] [dir='ltr'] {
|
||||
direction: rtl !important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export const StarsAndForks: FC<StarsAndForksInterface> = (props) => {
|
|||
</div>
|
||||
</div>
|
||||
<div className="flex-1 relative">
|
||||
<div className="absolute w-full h-full left-0 top-0">
|
||||
<div className="absolute w-full h-full start-0 top-0">
|
||||
{item.stars.length ? (
|
||||
<Chart list={item.stars} />
|
||||
) : (
|
||||
|
|
@ -84,7 +84,7 @@ export const StarsAndForks: FC<StarsAndForksInterface> = (props) => {
|
|||
</div>
|
||||
</div>
|
||||
<div className="flex-1 relative">
|
||||
<div className="absolute w-full h-full left-0 top-0">
|
||||
<div className="absolute w-full h-full start-0 top-0">
|
||||
{item.forks.length ? (
|
||||
<Chart list={item.forks} />
|
||||
) : (
|
||||
|
|
@ -143,7 +143,7 @@ export const StarsAndForks: FC<StarsAndForksInterface> = (props) => {
|
|||
</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="w-[2px] h-[30px] bg-customColor11 mr-[16px]"></div>
|
||||
<div className="w-[2px] h-[30px] bg-customColor11 me-[16px]"></div>
|
||||
<div className="text-[24px] flex-1">
|
||||
<UtcToLocalDateRender
|
||||
date={
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ export function Activate() {
|
|||
return (
|
||||
<>
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-left mb-4 cursor-pointer">
|
||||
<h1 className="text-3xl font-bold text-start mb-4 cursor-pointer">
|
||||
{t('activate_your_account', 'Activate your account')}
|
||||
</h1>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export function ForgotReturn({ token }: { token: string }) {
|
|||
<FormProvider {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-left mb-4 cursor-pointer">
|
||||
<h1 className="text-3xl font-bold text-start mb-4 cursor-pointer">
|
||||
{t('forgot_password_1', 'Forgot Password')}
|
||||
</h1>
|
||||
</div>
|
||||
|
|
@ -87,7 +87,7 @@ export function ForgotReturn({ token }: { token: string }) {
|
|||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="text-left mt-6">
|
||||
<div className="text-start mt-6">
|
||||
{t(
|
||||
'we_successfully_reset_your_password_you_can_now_login_with_your',
|
||||
'We successfully reset your password. You can now login with your'
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export function Forgot() {
|
|||
<FormProvider {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-left mb-4 cursor-pointer">
|
||||
<h1 className="text-3xl font-bold text-start mb-4 cursor-pointer">
|
||||
{t('forgot_password_1', 'Forgot Password')}
|
||||
</h1>
|
||||
</div>
|
||||
|
|
@ -68,7 +68,7 @@ export function Forgot() {
|
|||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="text-left mt-6">
|
||||
<div className="text-start mt-6">
|
||||
{t(
|
||||
'we_have_send_you_an_email_with_a_link_to_reset_your_password',
|
||||
'We have send you an email with a link to reset your password.'
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ export function Login() {
|
|||
<FormProvider {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-left mb-4 cursor-pointer">
|
||||
<h1 className="text-3xl font-bold text-start mb-4 cursor-pointer">
|
||||
{t('sign_in', 'Sign In')}
|
||||
</h1>
|
||||
</div>
|
||||
|
|
@ -76,7 +76,7 @@ export function Login() {
|
|||
<div className="h-[20px] mb-[24px] mt-[24px] relative">
|
||||
<div className="absolute w-full h-[1px] bg-fifth top-[50%] -translate-y-[50%]" />
|
||||
<div
|
||||
className={`absolute z-[1] ${interClass} justify-center items-center w-full left-0 top-0 flex`}
|
||||
className={`absolute z-[1] ${interClass} justify-center items-center w-full start-0 top-0 flex`}
|
||||
>
|
||||
<div className="bg-customColor15 px-[16px]">{t('or', 'OR')}</div>
|
||||
</div>
|
||||
|
|
@ -85,12 +85,14 @@ export function Login() {
|
|||
<div className="text-textColor">
|
||||
<Input
|
||||
label="Email"
|
||||
translationKey="label_email"
|
||||
{...form.register('email')}
|
||||
type="email"
|
||||
placeholder="Email Address"
|
||||
/>
|
||||
<Input
|
||||
label="Password"
|
||||
translationKey="label_password"
|
||||
{...form.register('password')}
|
||||
autoComplete="off"
|
||||
type="password"
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ export function RegisterAfter({
|
|||
<FormProvider {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-left mb-4 cursor-pointer">
|
||||
<h1 className="text-3xl font-bold text-start mb-4 cursor-pointer">
|
||||
{t('sign_up', 'Sign Up')}
|
||||
</h1>
|
||||
</div>
|
||||
|
|
@ -169,7 +169,7 @@ export function RegisterAfter({
|
|||
<div className="h-[20px] mb-[24px] mt-[24px] relative">
|
||||
<div className="absolute w-full h-[1px] bg-fifth top-[50%] -translate-y-[50%]" />
|
||||
<div
|
||||
className={`absolute z-[1] ${interClass} justify-center items-center w-full left-0 top-0 flex`}
|
||||
className={`absolute z-[1] ${interClass} justify-center items-center w-full start-0 top-0 flex`}
|
||||
>
|
||||
<div className="bg-customColor15 px-[16px]">{t('or', 'OR')}</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -41,7 +41,15 @@ export const Autopost: FC = () => {
|
|||
);
|
||||
const deleteHook = useCallback(
|
||||
(data: any) => async () => {
|
||||
if (await deleteDialog(`Are you sure you want to delete ${data.name}?`)) {
|
||||
if (
|
||||
await deleteDialog(
|
||||
t(
|
||||
'are_you_sure_you_want_to_delete',
|
||||
`Are you sure you want to delete ${data.name}?`,
|
||||
{ name: data.name }
|
||||
)
|
||||
)
|
||||
) {
|
||||
await fetch(`/autopost/${data.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
|
|
@ -285,7 +293,7 @@ export const AddOrEditWebhook: FC<{
|
|||
<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 right-[20px] top-[15px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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}
|
||||
>
|
||||
|
|
@ -306,10 +314,19 @@ export const AddOrEditWebhook: FC<{
|
|||
</button>
|
||||
|
||||
<div>
|
||||
<Input label="Title" {...form.register('title')} />
|
||||
<Input label="URL" {...form.register('url')} />
|
||||
<Input
|
||||
label="Title"
|
||||
translationKey="label_title"
|
||||
{...form.register('title')}
|
||||
/>
|
||||
<Input
|
||||
label="URL"
|
||||
translationKey="label_url"
|
||||
{...form.register('url')}
|
||||
/>
|
||||
<Select
|
||||
label="Should we sync the current last post?"
|
||||
translationKey="label_should_sync_last_post"
|
||||
{...form.register('syncLast', {
|
||||
setValueAs: (value) => {
|
||||
return value === 'true' || value === true;
|
||||
|
|
@ -324,6 +341,7 @@ export const AddOrEditWebhook: FC<{
|
|||
</Select>
|
||||
<Select
|
||||
label="When should we post it?"
|
||||
translationKey="label_when_post"
|
||||
{...form.register('onSlot', {
|
||||
setValueAs: (value) => value === 'true' || value === true,
|
||||
})}
|
||||
|
|
@ -336,6 +354,7 @@ export const AddOrEditWebhook: FC<{
|
|||
</Select>
|
||||
<Select
|
||||
label="Autogenerate content"
|
||||
translationKey="label_autogenerate_content"
|
||||
{...form.register('generateContent', {
|
||||
setValueAs: (value) => value === 'true' || value === true,
|
||||
})}
|
||||
|
|
@ -370,6 +389,7 @@ export const AddOrEditWebhook: FC<{
|
|||
)}
|
||||
<Select
|
||||
label="Generate Picture?"
|
||||
translationKey="label_generate_picture"
|
||||
{...form.register('addPicture', {
|
||||
setValueAs: (value) => value === 'true' || value === true,
|
||||
})}
|
||||
|
|
@ -384,6 +404,7 @@ export const AddOrEditWebhook: FC<{
|
|||
value={allIntegrations.value}
|
||||
name="integrations"
|
||||
label="Integrations"
|
||||
translationKey="label_integrations"
|
||||
disableForm={true}
|
||||
onChange={changeIntegration}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -9,39 +9,60 @@ import { useT } from '@gitroom/react/translation/get.transation.service.client';
|
|||
const useFaqList = () => {
|
||||
const { isGeneral } = useVariables();
|
||||
const user = useUser();
|
||||
const t = useT();
|
||||
return [
|
||||
...(user?.allowTrial
|
||||
? [
|
||||
{
|
||||
title: 'Am I going to be charged by Postiz?',
|
||||
description:
|
||||
'To confirm credit card information Postiz will hold $2 and release it immediately',
|
||||
title: t(
|
||||
'faq_am_i_going_to_be_charged_by_postiz',
|
||||
'Am I going to be charged by Postiz?'
|
||||
),
|
||||
description: t(
|
||||
'faq_to_confirm_credit_card_information_postiz_will_hold',
|
||||
'To confirm credit card information Postiz will hold $2 and release it immediately'
|
||||
),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
title: `Can I trust ${isGeneral ? 'Postiz' : 'Gitroom'}?`,
|
||||
description: `${
|
||||
isGeneral ? 'Postiz' : 'Gitroom'
|
||||
} is proudly open-source! We believe in an ethical and transparent culture, meaning that ${
|
||||
isGeneral ? 'Postiz' : 'Gitroom'
|
||||
} will live forever. You can check out the entire code or use it for personal projects. To view the open-source repository, <a href="https://github.com/gitroomhq/postiz-app" target="_blank" style="text-decoration: underline;">click here</a>.`,
|
||||
title: t(
|
||||
'faq_can_i_trust_postiz_gitroom',
|
||||
`Can I trust ${isGeneral ? 'Postiz' : 'Gitroom'}?`
|
||||
),
|
||||
description: t(
|
||||
'faq_postiz_gitroom_is_proudly_open_source',
|
||||
`${
|
||||
isGeneral ? 'Postiz' : 'Gitroom'
|
||||
} is proudly open-source! We believe in an ethical and transparent culture, meaning that ${
|
||||
isGeneral ? 'Postiz' : 'Gitroom'
|
||||
} will live forever. You can check out the entire code or use it for personal projects. To view the open-source repository, <a href="https://github.com/gitroomhq/postiz-app" target="_blank" style="text-decoration: underline;">click here</a>.`
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'What are channels?',
|
||||
description: `${
|
||||
isGeneral ? 'Postiz' : 'Gitroom'
|
||||
} allows you to schedule your posts between different channels.
|
||||
title: t('faq_what_are_channels', 'What are channels?'),
|
||||
description: t(
|
||||
'faq_postiz_gitroom_allows_you_to_schedule_posts',
|
||||
`${
|
||||
isGeneral ? 'Postiz' : 'Gitroom'
|
||||
} allows you to schedule your posts between different channels.
|
||||
A channel is a publishing platform where you can schedule your posts.
|
||||
For example, you can schedule your posts on X, Facebook, Instagram, TikTok, YouTube, Reddit, Linkedin, Dribbble, Threads and Pinterest.`,
|
||||
For example, you can schedule your posts on X, Facebook, Instagram, TikTok, YouTube, Reddit, Linkedin, Dribbble, Threads and Pinterest.`
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'What are team members?',
|
||||
description: `If you have a team with multiple members, you can invite them to your workspace to collaborate on your posts and add their personal channels`,
|
||||
title: t('faq_what_are_team_members', 'What are team members?'),
|
||||
description: t(
|
||||
'faq_if_you_have_a_team_with_multiple_members',
|
||||
'If you have a team with multiple members, you can invite them to your workspace to collaborate on your posts and add their personal channels'
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'What is AI auto-complete?',
|
||||
description: `We automate ChatGPT to help you write your social posts and articles`,
|
||||
title: t('faq_what_is_ai_auto_complete', 'What is AI auto-complete?'),
|
||||
description: t(
|
||||
'faq_we_automate_chatgpt_to_help_you_write',
|
||||
'We automate ChatGPT to help you write your social posts and articles'
|
||||
),
|
||||
},
|
||||
];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -175,6 +175,7 @@ export const LifetimeDeal = () => {
|
|||
<div className="flex-1">
|
||||
<Input
|
||||
label="Code"
|
||||
translationKey="label_code"
|
||||
placeholder="Enter your code"
|
||||
disableForm={true}
|
||||
name="code"
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ const Info: FC<{
|
|||
<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="Oh no" />
|
||||
<button
|
||||
className="outline-none absolute right-[20px] top-[15px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
@ -461,7 +461,7 @@ export const MainBillingComponent: FC<{
|
|||
(user?.tier === 'FREE' ||
|
||||
user?.tier?.current === 'FREE') &&
|
||||
user.allowTrial
|
||||
? 'Start 7 days free trial'
|
||||
? t('start_7_days_free_trial', 'Start 7 days free trial')
|
||||
: 'Purchase'}
|
||||
</Button>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -312,8 +312,11 @@ export const AddEditModal: FC<{
|
|||
}
|
||||
if (
|
||||
await deleteDialog(
|
||||
'Are you sure you want to close this modal? (all data will be lost)',
|
||||
'Yes, close it!'
|
||||
t(
|
||||
'are_you_sure_you_want_to_close_this_modal_all_data_will_be_lost',
|
||||
'Are you sure you want to close this modal? (all data will be lost)'
|
||||
),
|
||||
t('yes_close_it', 'Yes, close it!')
|
||||
)
|
||||
) {
|
||||
if (customClose) {
|
||||
|
|
@ -595,7 +598,7 @@ Here are the things you can do:
|
|||
}}
|
||||
>
|
||||
{uploading && (
|
||||
<div className="absolute left-0 top-0 w-full h-full bg-black/40 z-[600] flex justify-center items-center">
|
||||
<div className="absolute start-0 top-0 w-full h-full bg-black/40 z-[600] flex justify-center items-center">
|
||||
<LoadingComponent width={100} height={100} />
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -668,13 +671,13 @@ Here are the things you can do:
|
|||
{selectedIntegrations?.[0]?.identifier === 'youtube' ? (
|
||||
<img
|
||||
src="/icons/platforms/youtube.svg"
|
||||
className="absolute z-10 -bottom-[5px] -right-[5px]"
|
||||
className="absolute z-10 -bottom-[5px] -end-[5px]"
|
||||
width={20}
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
src={`/icons/platforms/${selectedIntegrations?.[0]?.identifier}.png`}
|
||||
className="rounded-full absolute z-10 -bottom-[5px] -right-[5px] border border-fifth"
|
||||
className="rounded-full absolute z-10 -bottom-[5px] -end-[5px] border border-fifth"
|
||||
alt={selectedIntegrations?.[0]?.identifier}
|
||||
width={20}
|
||||
height={20}
|
||||
|
|
@ -727,7 +730,7 @@ Here are the things you can do:
|
|||
<div className="flex-1">
|
||||
<MultiMediaComponent
|
||||
text={p.content}
|
||||
label="Attachments"
|
||||
label={t('attachments', 'Attachments')}
|
||||
description=""
|
||||
value={p.image}
|
||||
name="image"
|
||||
|
|
@ -756,7 +759,7 @@ Here are the things you can do:
|
|||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="text-[12px] font-[500] pr-[10px]">
|
||||
<div className="text-[12px] font-[500] pe-[10px]">
|
||||
{t('delete_post', 'Delete Post')}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -789,7 +792,7 @@ Here are the things you can do:
|
|||
) : null}
|
||||
</div>
|
||||
<div className="relative min-h-[68px] flex flex-col rounded-[4px] border border-customColor6 bg-sixth">
|
||||
<div className="gap-[10px] relative flex flex-col justify-center items-center min-h-full pr-[16px]">
|
||||
<div className="gap-[10px] relative flex flex-col justify-center items-center min-h-full pe-[16px]">
|
||||
<div
|
||||
id="add-edit-post-dialog-buttons"
|
||||
className="flex flex-row flex-wrap w-full h-full gap-[10px] justify-end items-center"
|
||||
|
|
@ -829,17 +832,20 @@ Here are the things you can do:
|
|||
<div className="flex justify-center items-center gap-[5px] h-full">
|
||||
<div className="h-full flex items-center text-white">
|
||||
{!canSendForPublication
|
||||
? 'Not matching order'
|
||||
? t('not_matching_order', 'Not matching order')
|
||||
: postFor
|
||||
? 'Submit for order'
|
||||
? t('submit_for_order', 'Submit for order')
|
||||
: !existingData.integration
|
||||
? selectedIntegrations.length === 0
|
||||
? `Select channels from the circles above`
|
||||
: 'Add to calendar'
|
||||
? t(
|
||||
'select_channels_from_circles',
|
||||
'Select channels from the circles above'
|
||||
)
|
||||
: t('add_to_calendar', 'Add to calendar')
|
||||
: // @ts-ignore
|
||||
existingData?.posts?.[0]?.state === 'DRAFT'
|
||||
? 'Schedule'
|
||||
: 'Update'}
|
||||
? t('schedule', 'Schedule')
|
||||
: t('update', 'Update')}
|
||||
</div>
|
||||
{!postFor && (
|
||||
<div className="h-full flex items-center">
|
||||
|
|
@ -858,7 +864,7 @@ Here are the things you can do:
|
|||
<div
|
||||
onClick={postNow}
|
||||
className={clsx(
|
||||
'hidden group-hover:flex hover:flex flex-col justify-center absolute left-0 top-[100%] w-full h-[40px] bg-customColor22 border border-tableBorder',
|
||||
'hidden group-hover:flex hover:flex flex-col justify-center absolute start-0 top-[100%] w-full h-[40px] bg-customColor22 border border-tableBorder',
|
||||
loading &&
|
||||
'cursor-not-allowed pointer-events-none opacity-50'
|
||||
)}
|
||||
|
|
@ -886,7 +892,7 @@ Here are the things you can do:
|
|||
<TopTitle title="" removeTitle={true}>
|
||||
<TagsComponent
|
||||
name="tags"
|
||||
label="Tags"
|
||||
label={t('tags', 'Tags')}
|
||||
initial={tags}
|
||||
onChange={(e) => setTags(e.target.value)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ export const AddProviderButton: FC<{
|
|||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="flex-1 text-left">{t('add_channel', 'Add Channel')}</div>
|
||||
<div className="flex-1 text-start">{t('add_channel', 'Add Channel')}</div>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
|
@ -115,7 +115,7 @@ export const ApiModal: FC<{
|
|||
<TopTitle title={`Add API key for ${name}`} />
|
||||
<button
|
||||
onClick={close}
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
@ -167,7 +167,7 @@ export const UrlModal: FC<{
|
|||
<TopTitle title={`Instance URL`} />
|
||||
<button
|
||||
onClick={close}
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
@ -265,7 +265,7 @@ export const CustomVariables: FC<{
|
|||
<TopTitle title={`Custom URL`} />
|
||||
<button
|
||||
onClick={close || modals.closeAll}
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
@ -448,7 +448,7 @@ export const AddProviderComponent: FC<{
|
|||
<TopTitle title="Add Channel" />
|
||||
<button
|
||||
onClick={close}
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
@ -506,7 +506,7 @@ export const AddProviderComponent: FC<{
|
|||
viewBox="0 0 26 26"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="absolute top-[10px] right-[10px]"
|
||||
className="absolute top-[10px] end-[10px]"
|
||||
>
|
||||
<path
|
||||
d="M13 0C10.4288 0 7.91543 0.762437 5.77759 2.1909C3.63975 3.61935 1.97351 5.64968 0.989572 8.02512C0.0056327 10.4006 -0.251811 13.0144 0.249797 15.5362C0.751405 18.0579 1.98953 20.3743 3.80762 22.1924C5.6257 24.0105 7.94208 25.2486 10.4638 25.7502C12.9856 26.2518 15.5995 25.9944 17.9749 25.0104C20.3503 24.0265 22.3807 22.3603 23.8091 20.2224C25.2376 18.0846 26 15.5712 26 13C25.9964 9.5533 24.6256 6.24882 22.1884 3.81163C19.7512 1.37445 16.4467 0.00363977 13 0ZM13 21C12.7033 21 12.4133 20.912 12.1667 20.7472C11.92 20.5824 11.7277 20.3481 11.6142 20.074C11.5007 19.7999 11.471 19.4983 11.5288 19.2074C11.5867 18.9164 11.7296 18.6491 11.9393 18.4393C12.1491 18.2296 12.4164 18.0867 12.7074 18.0288C12.9983 17.9709 13.2999 18.0007 13.574 18.1142C13.8481 18.2277 14.0824 18.42 14.2472 18.6666C14.412 18.9133 14.5 19.2033 14.5 19.5C14.5 19.8978 14.342 20.2794 14.0607 20.5607C13.7794 20.842 13.3978 21 13 21ZM14 14.91V15C14 15.2652 13.8946 15.5196 13.7071 15.7071C13.5196 15.8946 13.2652 16 13 16C12.7348 16 12.4804 15.8946 12.2929 15.7071C12.1054 15.5196 12 15.2652 12 15V14C12 13.7348 12.1054 13.4804 12.2929 13.2929C12.4804 13.1054 12.7348 13 13 13C14.6538 13 16 11.875 16 10.5C16 9.125 14.6538 8 13 8C11.3463 8 10 9.125 10 10.5V11C10 11.2652 9.89465 11.5196 9.70711 11.7071C9.51958 11.8946 9.26522 12 9.00001 12C8.73479 12 8.48044 11.8946 8.2929 11.7071C8.10536 11.5196 8.00001 11.2652 8.00001 11V10.5C8.00001 8.01875 10.2425 6 13 6C15.7575 6 18 8.01875 18 10.5C18 12.6725 16.28 14.4913 14 14.91Z"
|
||||
|
|
|
|||
|
|
@ -64,12 +64,12 @@ ${type}
|
|||
}
|
||||
: {})}
|
||||
className={clsx(
|
||||
'relative ml-[10px] rounded-[4px] mb-[10px] gap-[8px] !text-primary justify-center items-center flex border border-dashed border-customColor21 bg-input',
|
||||
'relative ms-[10px] rounded-[4px] mb-[10px] gap-[8px] !text-primary justify-center items-center flex border border-dashed border-customColor21 bg-input',
|
||||
value.length < 30 && 'opacity-25'
|
||||
)}
|
||||
>
|
||||
{loading && (
|
||||
<div className="absolute left-[50%] -translate-x-[50%]">
|
||||
<div className="absolute start-[50%] -translate-x-[50%]">
|
||||
<Loading height={30} width={30} type="spin" color="#fff" />
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -99,7 +99,7 @@ ${type}
|
|||
</div>
|
||||
</Button>
|
||||
{value.length >= 30 && !loading && (
|
||||
<div className="text-[12px] ml-[10px] -mt-[10px] w-[200px] absolute top-[100%] z-[500] left-0 hidden group-hover:block">
|
||||
<div className="text-[12px] ms-[10px] -mt-[10px] w-[200px] absolute top-[100%] z-[500] start-0 hidden group-hover:block">
|
||||
<ul className="cursor-pointer rounded-[4px] border border-dashed border-customColor21 mt-[3px] p-[5px] bg-customColor2">
|
||||
{list.map((p) => (
|
||||
<li onClick={generateImage(p)} key={p} className="hover:bg-sixth">
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ export const BotPicture: FC<{
|
|||
<div className="rounded-[4px] border border-customColor6 bg-sixth px-[16px] pb-[16px] relative w-full">
|
||||
<TopTitle title={`Change Bot Picture`} />
|
||||
<button
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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()}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ import {
|
|||
useCalendar,
|
||||
} from '@gitroom/frontend/components/launches/calendar.context';
|
||||
import dayjs from 'dayjs';
|
||||
import 'dayjs/locale/en';
|
||||
import 'dayjs/locale/he';
|
||||
import localizedFormat from 'dayjs/plugin/localizedFormat';
|
||||
import { useModals } from '@mantine/modals';
|
||||
import { AddEditModal } from '@gitroom/frontend/components/launches/add.edit.model';
|
||||
import clsx from 'clsx';
|
||||
|
|
@ -37,8 +40,27 @@ import removeMd from 'remove-markdown';
|
|||
import { useInterval } from '@mantine/hooks';
|
||||
import { StatisticsModal } from '@gitroom/frontend/components/launches/statistics';
|
||||
import { useT } from '@gitroom/react/translation/get.transation.service.client';
|
||||
import i18next from 'i18next';
|
||||
|
||||
// Extend dayjs with necessary plugins
|
||||
extend(isSameOrAfter);
|
||||
extend(isSameOrBefore);
|
||||
extend(localizedFormat);
|
||||
|
||||
// Initialize language
|
||||
const updateDayjsLocale = () => {
|
||||
const currentLanguage = i18next.resolvedLanguage || 'en';
|
||||
dayjs.locale(currentLanguage);
|
||||
};
|
||||
|
||||
// Set dayjs locale whenever i18next language changes
|
||||
i18next.on('languageChanged', () => {
|
||||
updateDayjsLocale();
|
||||
});
|
||||
|
||||
// Initial setup
|
||||
updateDayjsLocale();
|
||||
|
||||
const convertTimeFormatBasedOnLocality = (time: number) => {
|
||||
if (isUSCitizen()) {
|
||||
return `${time === 12 ? 12 : time % 12}:00 ${time >= 12 ? 'PM' : 'AM'}`;
|
||||
|
|
@ -66,6 +88,11 @@ export const DayView = () => {
|
|||
const calendar = useCalendar();
|
||||
const { integrations, posts, currentYear, currentDay, currentWeek } =
|
||||
calendar;
|
||||
|
||||
// Set dayjs locale based on current language
|
||||
const currentLanguage = i18next.resolvedLanguage || 'en';
|
||||
dayjs.locale(currentLanguage);
|
||||
|
||||
const options = useMemo(() => {
|
||||
const createdPosts = posts.map((post) => ({
|
||||
integration: [integrations.find((i) => i.id === post.integration.id)!],
|
||||
|
|
@ -109,7 +136,7 @@ export const DayView = () => {
|
|||
.startOf('day')
|
||||
.add(option[0].time, 'minute')
|
||||
.local()
|
||||
.format(isUSCitizen() ? 'hh:mm A' : 'HH:mm')}
|
||||
.format(isUSCitizen() ? 'hh:mm A' : 'LT')}
|
||||
</div>
|
||||
<div
|
||||
key={option[0].time}
|
||||
|
|
@ -142,23 +169,35 @@ export const WeekView = () => {
|
|||
const { currentYear, currentWeek } = useCalendar();
|
||||
const t = useT();
|
||||
|
||||
// Use dayjs to get localized day names
|
||||
const localizedDays = useMemo(() => {
|
||||
const currentLanguage = i18next.resolvedLanguage || 'en';
|
||||
dayjs.locale(currentLanguage);
|
||||
|
||||
const days = [];
|
||||
// Starting from Monday (1) to Sunday (7)
|
||||
for (let i = 1; i <= 7; i++) {
|
||||
days.push(dayjs().day(i).format('dddd'));
|
||||
}
|
||||
return days;
|
||||
}, [i18next.resolvedLanguage]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-screen overflow-hidden text-textColor flex-1">
|
||||
<div className="flex-1">
|
||||
<div className="grid grid-cols-8 bg-customColor31 gap-[1px] border-customColor31 border rounded-[10px]">
|
||||
<div className="bg-customColor20 sticky top-0 z-10 bg-gray-900"></div>
|
||||
{days.map((day, index) => (
|
||||
{localizedDays.map((day, index) => (
|
||||
<div
|
||||
key={day}
|
||||
className="sticky top-0 z-10 bg-customColor20 p-2 text-center"
|
||||
>
|
||||
<div>{t(day.toLowerCase(), day)}</div>
|
||||
<div>{day}</div>
|
||||
</div>
|
||||
))}
|
||||
{hours.map((hour) => (
|
||||
<Fragment key={hour}>
|
||||
<div className="p-2 pr-4 bg-secondary text-center items-center justify-center flex">
|
||||
{/* {hour.toString().padStart(2, '0')}:00 */}
|
||||
<div className="p-2 pe-4 bg-secondary text-center items-center justify-center flex">
|
||||
{convertTimeFormatBasedOnLocality(hour)}
|
||||
</div>
|
||||
{days.map((day, indexDay) => (
|
||||
|
|
@ -186,6 +225,19 @@ export const MonthView = () => {
|
|||
const { currentYear, currentMonth } = useCalendar();
|
||||
const t = useT();
|
||||
|
||||
// Use dayjs to get localized day names
|
||||
const localizedDays = useMemo(() => {
|
||||
const currentLanguage = i18next.resolvedLanguage || 'en';
|
||||
dayjs.locale(currentLanguage);
|
||||
|
||||
const days = [];
|
||||
// Starting from Monday (1) to Sunday (7)
|
||||
for (let i = 1; i <= 7; i++) {
|
||||
days.push(dayjs().day(i).format('dddd'));
|
||||
}
|
||||
return days;
|
||||
}, [i18next.resolvedLanguage]);
|
||||
|
||||
const calendarDays = useMemo(() => {
|
||||
const startOfMonth = dayjs(new Date(currentYear, currentMonth, 1));
|
||||
|
||||
|
|
@ -213,16 +265,17 @@ export const MonthView = () => {
|
|||
}
|
||||
return calendarDays;
|
||||
}, [currentYear, currentMonth]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-screen overflow-hidden text-textColor flex-1">
|
||||
<div className="flex-1 flex">
|
||||
<div className="grid grid-cols-7 grid-rows-[40px_auto] bg-customColor31 gap-[1px] border-customColor31 border rounded-[10px] flex-1">
|
||||
{days.map((day) => (
|
||||
{localizedDays.map((day) => (
|
||||
<div
|
||||
key={day}
|
||||
className="sticky top-0 z-10 bg-customColor20 p-2 text-center"
|
||||
>
|
||||
<div>{t(day.toLowerCase(), day)}</div>
|
||||
<div>{day}</div>
|
||||
</div>
|
||||
))}
|
||||
{calendarDays.map((date, index) => (
|
||||
|
|
@ -618,7 +671,7 @@ export const CalendarColumn: FC<{
|
|||
display === ('month' as any)
|
||||
? 'flex-1 min-h-[40px] w-full'
|
||||
: !postList.length
|
||||
? 'h-full w-full absolute left-0 top-0 p-[5px]'
|
||||
? 'h-full w-full absolute start-0 top-0 p-[5px]'
|
||||
: 'min-h-[40px] w-full',
|
||||
'flex items-center justify-center cursor-pointer pb-[2.5px]'
|
||||
)}
|
||||
|
|
@ -656,13 +709,13 @@ export const CalendarColumn: FC<{
|
|||
{selectedIntegrations.identifier === 'youtube' ? (
|
||||
<img
|
||||
src="/icons/platforms/youtube.svg"
|
||||
className="absolute z-10 -bottom-[5px] -right-[5px]"
|
||||
className="absolute z-10 -bottom-[5px] -end-[5px]"
|
||||
width={20}
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
src={`/icons/platforms/${selectedIntegrations.identifier}.png`}
|
||||
className="rounded-full absolute z-10 -bottom-[5px] -right-[5px] border border-fifth"
|
||||
className="rounded-full absolute z-10 -bottom-[5px] -end-[5px] border border-fifth"
|
||||
alt={selectedIntegrations.identifier}
|
||||
width={20}
|
||||
height={20}
|
||||
|
|
@ -795,15 +848,15 @@ const CalendarItem: FC<{
|
|||
src={post.integration.picture! || '/no-picture.jpg'}
|
||||
/>
|
||||
<img
|
||||
className="w-[12px] h-[12px] rounded-full absolute z-10 top-[10px] right-0 border border-fifth"
|
||||
className="w-[12px] h-[12px] rounded-full absolute z-10 top-[10px] end-0 border border-fifth"
|
||||
src={`/icons/platforms/${post.integration?.providerIdentifier}.png`}
|
||||
/>
|
||||
</div>
|
||||
<div className="whitespace-nowrap line-clamp-2">
|
||||
<div className="text-left">
|
||||
<div className="text-start">
|
||||
{state === 'DRAFT' ? t('draft', 'Draft') + ': ' : ''}
|
||||
</div>
|
||||
<div className="w-full overflow-hidden overflow-ellipsis text-left">
|
||||
<div className="w-full overflow-hidden overflow-ellipsis text-start">
|
||||
{removeMd(post.content).replace(/\n/g, ' ')}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ export const CommentComponent: FC<{
|
|||
<TopTitle title={`Comments for ${date.format('DD/MM/YYYY HH:mm')}`} />
|
||||
<button
|
||||
onClick={closeAll}
|
||||
className="outline-none absolute right-[20px] top-[15px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
@ -357,7 +357,7 @@ export const CommentComponent: FC<{
|
|||
<div className="flex">
|
||||
<div className="relative w-[40px] flex flex-col items-center">
|
||||
<div className="h-[30px] w-[2px] bg-customColor25 absolute top-0 z-[1]" />
|
||||
<div className="h-[2px] w-[21px] bg-customColor25 absolute top-[30px] right-0 z-[1]" />
|
||||
<div className="h-[2px] w-[21px] bg-customColor25 absolute top-[30px] end-0 z-[1]" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<CommentBox
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export const CustomerModal: FC<{
|
|||
<div className="rounded-[4px] border border-customColor6 bg-sixth px-[16px] pb-[16px] relative w-full">
|
||||
<TopTitle title={`Move / Add to customer`} />
|
||||
<button
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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()}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ export const Editor = forwardRef<
|
|||
{t('', '\uD83D\uDE00')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute z-[200] right-0">
|
||||
<div className="absolute z-[200] end-0">
|
||||
<EmojiPicker
|
||||
theme={(localStorage.getItem('mode') as Theme) || Theme.DARK}
|
||||
onEmojiClick={(e) => {
|
||||
|
|
@ -105,7 +105,7 @@ export const Editor = forwardRef<
|
|||
props?.onChange?.(e.target.value);
|
||||
}}
|
||||
onPaste={props.onPaste}
|
||||
placeholder="Write your reply..."
|
||||
placeholder={t('write_your_reply', 'Write your reply...')}
|
||||
autosuggestionsConfig={{
|
||||
textareaPurpose: `Assist me in writing social media posts.`,
|
||||
chatApiConfigs: {},
|
||||
|
|
|
|||
|
|
@ -7,39 +7,46 @@ import { useCallback } from 'react';
|
|||
import { isUSCitizen } from './helpers/isuscitizen.utils';
|
||||
import { SelectCustomer } from '@gitroom/frontend/components/launches/select.customer';
|
||||
import { useT } from '@gitroom/react/translation/get.transation.service.client';
|
||||
import i18next from 'i18next';
|
||||
|
||||
export const Filters = () => {
|
||||
const week = useCalendar();
|
||||
const t = useT();
|
||||
|
||||
// Set dayjs locale based on current language
|
||||
const currentLanguage = i18next.resolvedLanguage || 'en';
|
||||
dayjs.locale(currentLanguage);
|
||||
|
||||
const betweenDates =
|
||||
week.display === 'day'
|
||||
? dayjs()
|
||||
.year(week.currentYear)
|
||||
.isoWeek(week.currentWeek)
|
||||
.day(week.currentDay)
|
||||
.format(isUSCitizen() ? 'MM/DD/YYYY' : 'DD/MM/YYYY')
|
||||
.format('L')
|
||||
: week.display === 'week'
|
||||
? dayjs()
|
||||
.year(week.currentYear)
|
||||
.isoWeek(week.currentWeek)
|
||||
.startOf('isoWeek')
|
||||
.format(isUSCitizen() ? 'MM/DD/YYYY' : 'DD/MM/YYYY') +
|
||||
.format('L') +
|
||||
' - ' +
|
||||
dayjs()
|
||||
.year(week.currentYear)
|
||||
.isoWeek(week.currentWeek)
|
||||
.endOf('isoWeek')
|
||||
.format(isUSCitizen() ? 'MM/DD/YYYY' : 'DD/MM/YYYY')
|
||||
.format('L')
|
||||
: dayjs()
|
||||
.year(week.currentYear)
|
||||
.month(week.currentMonth)
|
||||
.startOf('month')
|
||||
.format(isUSCitizen() ? 'MM/DD/YYYY' : 'DD/MM/YYYY') +
|
||||
.format('L') +
|
||||
' - ' +
|
||||
dayjs()
|
||||
.year(week.currentYear)
|
||||
.month(week.currentMonth)
|
||||
.endOf('month')
|
||||
.format(isUSCitizen() ? 'MM/DD/YYYY' : 'DD/MM/YYYY');
|
||||
.format('L');
|
||||
const setDay = useCallback(() => {
|
||||
week.setFilters({
|
||||
currentDay: +dayjs().day() as 0 | 1 | 2 | 3 | 4 | 5 | 6,
|
||||
|
|
@ -162,7 +169,7 @@ export const Filters = () => {
|
|||
return (
|
||||
<div className="text-textColor flex flex-col md:flex-row gap-[8px] items-center select-none">
|
||||
<div className="flex flex-grow flex-row">
|
||||
<div onClick={previous} className="cursor-pointer text-textColor">
|
||||
<div onClick={previous} className="cursor-pointer text-textColor rtl:rotate-180">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
|
|
@ -184,10 +191,10 @@ export const Filters = () => {
|
|||
.day(week.currentDay)
|
||||
.format('dddd')}`
|
||||
: week.display === 'week'
|
||||
? `Week ${week.currentWeek}`
|
||||
: `${dayjs().month(week.currentMonth).format('MMMM')}`}
|
||||
? t('week_number', 'Week {{number}}', { number: week.currentWeek })
|
||||
: dayjs().month(week.currentMonth).format('MMMM')}
|
||||
</div>
|
||||
<div onClick={next} className="cursor-pointer text-textColor">
|
||||
<div onClick={next} className="cursor-pointer text-textColor rtl:rotate-180">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ export const GeneralPreviewComponent: FC<{
|
|||
<div className="h-[22px] text-[15px] font-[700]">
|
||||
{integration?.name}
|
||||
</div>
|
||||
<div className="text-[15px] text-customColor26 mt-[1px] ml-[2px]">
|
||||
<div className="text-[15px] text-customColor26 mt-[1px] ms-[2px]">
|
||||
<svg
|
||||
viewBox="0 0 22 22"
|
||||
aria-label="Verified account"
|
||||
|
|
@ -68,7 +68,7 @@ export const GeneralPreviewComponent: FC<{
|
|||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="text-[15px] font-[400] text-customColor27 ml-[4px]">
|
||||
<div className="text-[15px] font-[400] text-customColor27 ms-[4px]">
|
||||
{integration?.display || '@username'}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -60,34 +60,48 @@ const FirstStep: FC = (props) => {
|
|||
const data = JSON.parse(chunk);
|
||||
switch (data.name) {
|
||||
case 'agent':
|
||||
setShowStep('Agent starting');
|
||||
setShowStep(t('agent_starting', 'Agent starting'));
|
||||
break;
|
||||
case 'research':
|
||||
setShowStep('Researching your content...');
|
||||
setShowStep(
|
||||
t('researching_your_content', 'Researching your content...')
|
||||
);
|
||||
break;
|
||||
case 'find-category':
|
||||
setShowStep('Understanding the category...');
|
||||
setShowStep(
|
||||
t(
|
||||
'understanding_the_category',
|
||||
'Understanding the category...'
|
||||
)
|
||||
);
|
||||
break;
|
||||
case 'find-topic':
|
||||
setShowStep('Finding the topic...');
|
||||
setShowStep(t('finding_the_topic', 'Finding the topic...'));
|
||||
break;
|
||||
case 'find-popular-posts':
|
||||
setShowStep('Finding popular posts to match with...');
|
||||
setShowStep(
|
||||
t(
|
||||
'finding_popular_posts_to_match_with',
|
||||
'Finding popular posts to match with...'
|
||||
)
|
||||
);
|
||||
break;
|
||||
case 'generate-hook':
|
||||
setShowStep('Generating hook...');
|
||||
setShowStep(t('generating_hook', 'Generating hook...'));
|
||||
break;
|
||||
case 'generate-content':
|
||||
setShowStep('Generating content...');
|
||||
setShowStep(t('generating_content', 'Generating content...'));
|
||||
break;
|
||||
case 'generate-picture':
|
||||
setShowStep('Generating pictures...');
|
||||
setShowStep(t('generating_pictures', 'Generating pictures...'));
|
||||
break;
|
||||
case 'upload-pictures':
|
||||
setShowStep('Uploading pictures...');
|
||||
setShowStep(t('uploading_pictures', 'Uploading pictures...'));
|
||||
break;
|
||||
case 'post-time':
|
||||
setShowStep('Finding time to post...');
|
||||
setShowStep(
|
||||
t('finding_time_to_post', 'Finding time to post...')
|
||||
);
|
||||
break;
|
||||
}
|
||||
lastResponse = data;
|
||||
|
|
@ -97,7 +111,7 @@ const FirstStep: FC = (props) => {
|
|||
}
|
||||
}
|
||||
},
|
||||
[]
|
||||
[t]
|
||||
);
|
||||
const onSubmit: SubmitHandler<{
|
||||
research: string;
|
||||
|
|
@ -182,12 +196,18 @@ const FirstStep: FC = (props) => {
|
|||
</div>
|
||||
)}
|
||||
<Textarea
|
||||
label="Write anything"
|
||||
label={t('write_anything', 'Write anything')}
|
||||
disabled={loading}
|
||||
placeholder="You can write anything you want, and also add links, we will do the research for you..."
|
||||
placeholder={t(
|
||||
'you_can_write_anything_you_want_and_also_add_links_we_will_do_the_research_for_you',
|
||||
'You can write anything you want, and also add links, we will do the research for you...'
|
||||
)}
|
||||
{...form.register('research')}
|
||||
/>
|
||||
<Select label="Output format" {...form.register('format')}>
|
||||
<Select
|
||||
label={t('output_format', 'Output format')}
|
||||
{...form.register('format')}
|
||||
>
|
||||
<option value="one_short">
|
||||
{t('short_post', 'Short post')}
|
||||
</option>
|
||||
|
|
@ -204,7 +224,10 @@ const FirstStep: FC = (props) => {
|
|||
{t('a_thread_with_long_posts', 'A thread with long posts')}
|
||||
</option>
|
||||
</Select>
|
||||
<Select label="Output format" {...form.register('tone')}>
|
||||
<Select
|
||||
label={t('output_format', 'Output format')}
|
||||
{...form.register('tone')}
|
||||
>
|
||||
<option value="personal">
|
||||
{t(
|
||||
'personal_voice_i_am_happy_to_announce',
|
||||
|
|
@ -224,7 +247,7 @@ const FirstStep: FC = (props) => {
|
|||
<Checkbox
|
||||
disabled={loading}
|
||||
{...form.register('isPicture')}
|
||||
label="Add pictures?"
|
||||
label={t('add_pictures', 'Add pictures?')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -255,7 +278,7 @@ export const GeneratorPopup = () => {
|
|||
<div className="bg-sixth p-[32px] w-full max-w-[920px] mx-auto flex flex-col rounded-[4px] border border-customColor6 relative">
|
||||
<button
|
||||
onClick={closeAll}
|
||||
className="outline-none absolute right-[20px] top-[15px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
@ -335,7 +358,7 @@ export const GeneratorComponent = () => {
|
|||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
<div className="flex-1 text-left">
|
||||
<div className="flex-1 text-start">
|
||||
{t('generate_posts', 'Generate Posts')}
|
||||
</div>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ export const DatePicker: FC<{
|
|||
{open && (
|
||||
<div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="animate-normalFadeDown absolute top-[100%] mt-[16px] right-0 bg-sixth border border-tableBorder text-textColor rounded-[16px] z-[300] p-[16px] flex flex-col"
|
||||
className="animate-normalFadeDown absolute top-[100%] mt-[16px] end-0 bg-sixth border border-tableBorder text-textColor rounded-[16px] z-[300] p-[16px] flex flex-col"
|
||||
>
|
||||
<Calendar
|
||||
onChange={changeDate('date')}
|
||||
|
|
|
|||
|
|
@ -97,14 +97,14 @@ export const LinkedinCompany: FC<{
|
|||
}
|
||||
};
|
||||
return (
|
||||
<div className="text-textColor fixed left-0 top-0 bg-primary/80 z-[300] w-full h-full p-[60px] animate-fade justify-center flex">
|
||||
<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">
|
||||
<div className="flex flex-col w-[500px] h-[250px] bg-sixth border-tableBorder border-2 rounded-xl pb-[20px] px-[20px] relative">
|
||||
<div className="flex">
|
||||
<div className="flex-1">
|
||||
<TopTitle title={'Select Company'} />
|
||||
</div>
|
||||
<button
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root bg-primary hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ export const PickPlatforms: FC<{
|
|||
!props.singleSelect ? (
|
||||
<div
|
||||
key={integration.id}
|
||||
className="flex gap-[8px] items-center mr-[10px]"
|
||||
className="flex gap-[8px] items-center me-[10px]"
|
||||
{...(props.toolTip && {
|
||||
'data-tooltip-id': 'tooltip',
|
||||
'data-tooltip-content': integration.name,
|
||||
|
|
@ -254,13 +254,13 @@ export const PickPlatforms: FC<{
|
|||
{integration.identifier === 'youtube' ? (
|
||||
<img
|
||||
src="/icons/platforms/youtube.svg"
|
||||
className="absolute z-10 -bottom-[5px] -right-[5px]"
|
||||
className="absolute z-10 -bottom-[5px] -end-[5px]"
|
||||
width={20}
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
src={`/icons/platforms/${integration.identifier}.png`}
|
||||
className="rounded-full absolute z-10 -bottom-[5px] -right-[5px] border border-fifth"
|
||||
className="rounded-full absolute z-10 -bottom-[5px] -end-[5px] border border-fifth"
|
||||
alt={integration.identifier}
|
||||
width={20}
|
||||
height={20}
|
||||
|
|
@ -292,7 +292,7 @@ export const PickPlatforms: FC<{
|
|||
/>
|
||||
<Image
|
||||
src={`/icons/platforms/${integration.identifier}.png`}
|
||||
className="rounded-full absolute z-10 -bottom-[5px] -right-[5px] border border-fifth"
|
||||
className="rounded-full absolute z-10 -bottom-[5px] -end-[5px] border border-fifth"
|
||||
alt={integration.identifier}
|
||||
width={15}
|
||||
height={15}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import { FC, ReactNode } from 'react';
|
||||
import { useT } from '@gitroom/react/translation/get.transation.service.client';
|
||||
|
||||
export const TopTitle: FC<{
|
||||
title: string;
|
||||
shouldExpend?: boolean;
|
||||
|
|
@ -9,9 +11,22 @@ export const TopTitle: FC<{
|
|||
}> = (props) => {
|
||||
const { title, removeTitle, children, shouldExpend, expend, collapse } =
|
||||
props;
|
||||
const t = useT();
|
||||
|
||||
// Translate the title using a key derived from the title itself
|
||||
// This creates a consistent key pattern for each title
|
||||
const translatedTitle = t(
|
||||
// Convert to lowercase, replace spaces with underscores
|
||||
`top_title_${title
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, '_')
|
||||
.replace(/[^\w]/g, '')}`,
|
||||
title
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="h-[57px] border-b flex items-center border-customColor6 px-[16px] -mx-[16px]">
|
||||
{!removeTitle && <div className="flex-1">{title}</div>}
|
||||
{!removeTitle && <div className="flex-1">{translatedTitle}</div>}
|
||||
{children}
|
||||
{shouldExpend !== undefined && (
|
||||
<div className="cursor-pointer">
|
||||
|
|
|
|||
|
|
@ -115,8 +115,8 @@ export const MenuGroupComponent: FC<
|
|||
ref={drop}
|
||||
>
|
||||
{collectedProps.isOver && (
|
||||
<div className="absolute left-0 top-0 w-full h-full pointer-events-none">
|
||||
<div className="w-full h-full left-0 top-0 relative">
|
||||
<div className="absolute start-0 top-0 w-full h-full pointer-events-none">
|
||||
<div className="w-full h-full start-0 top-0 relative">
|
||||
<div className="bg-white/30 w-full h-full p-[8px] box-content rounded-md" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -201,17 +201,17 @@ export const MenuComponent: FC<
|
|||
>
|
||||
{(integration.inBetweenSteps || integration.refreshNeeded) && (
|
||||
<div
|
||||
className="absolute left-0 top-0 w-[39px] h-[46px] cursor-pointer"
|
||||
className="absolute start-0 top-0 w-[39px] h-[46px] cursor-pointer"
|
||||
onClick={
|
||||
integration.refreshNeeded
|
||||
? refreshChannel(integration)
|
||||
: continueIntegration(integration)
|
||||
}
|
||||
>
|
||||
<div className="bg-red-500 w-[15px] h-[15px] rounded-full -left-[5px] -top-[5px] absolute z-[200] text-[10px] flex justify-center items-center">
|
||||
<div className="bg-red-500 w-[15px] h-[15px] rounded-full -start-[5px] -top-[5px] absolute z-[200] text-[10px] flex justify-center items-center">
|
||||
!
|
||||
</div>
|
||||
<div className="bg-primary/60 w-[39px] h-[46px] left-0 top-0 absolute rounded-full z-[199]" />
|
||||
<div className="bg-primary/60 w-[39px] h-[46px] start-0 top-0 absolute rounded-full z-[199]" />
|
||||
</div>
|
||||
)}
|
||||
<ImageWithFallback
|
||||
|
|
@ -225,13 +225,13 @@ export const MenuComponent: FC<
|
|||
{integration.identifier === 'youtube' ? (
|
||||
<img
|
||||
src="/icons/platforms/youtube.svg"
|
||||
className="absolute z-10 -bottom-[5px] -right-[5px]"
|
||||
className="absolute z-10 -bottom-[5px] -end-[5px]"
|
||||
width={20}
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
src={`/icons/platforms/${integration.identifier}.png`}
|
||||
className="rounded-full absolute z-10 -bottom-[5px] -right-[5px] border border-fifth"
|
||||
className="rounded-full absolute z-10 -bottom-[5px] -end-[5px] border border-fifth"
|
||||
alt={integration.identifier}
|
||||
width={20}
|
||||
height={20}
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@ export const Menu: FC<{
|
|||
{show && (
|
||||
<div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className={`absolute top-[100%] left-0 p-[8px] px-[20px] bg-fifth flex flex-col gap-[16px] z-[100] rounded-[8px] border border-tableBorder ${interClass} text-nowrap`}
|
||||
className={`absolute top-[100%] start-0 p-[8px] px-[20px] bg-fifth flex flex-col gap-[16px] z-[100] rounded-[8px] border border-tableBorder ${interClass} text-nowrap`}
|
||||
>
|
||||
{canDisable &&
|
||||
findIntegration?.refreshNeeded &&
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export const NewPost = () => {
|
|||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
<div className="flex-1 text-left">
|
||||
<div className="flex-1 text-start">
|
||||
{t('create_new_post', 'Create New Post')}
|
||||
</div>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ const Polonto: FC<{
|
|||
};
|
||||
}, []);
|
||||
return (
|
||||
<div className="fixed left-0 top-0 bg-primary/80 z-[300] w-full min-h-full px-[60px] animate-fade">
|
||||
<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">
|
||||
|
|
@ -100,7 +100,7 @@ const Polonto: FC<{
|
|||
</div>
|
||||
<button
|
||||
onClick={closeModal}
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root bg-primary hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ const HashnodePreview: FC = () => {
|
|||
{subtitle}
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-[60px] text-left">
|
||||
<div className="px-[60px] text-start">
|
||||
<MDEditor.Markdown
|
||||
style={{
|
||||
whiteSpace: 'pre-wrap',
|
||||
|
|
|
|||
|
|
@ -474,7 +474,7 @@ export const withProvider = function <T extends object>(
|
|||
createPortal(
|
||||
<EditorWrapper>
|
||||
{uploading && (
|
||||
<div className="absolute left-0 top-0 w-full h-full bg-black/40 z-[600] flex justify-center items-center">
|
||||
<div className="absolute start-0 top-0 w-full h-full bg-black/40 z-[600] flex justify-center items-center">
|
||||
<LoadingComponent width={100} height={100} />
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -571,7 +571,7 @@ export const withProvider = function <T extends object>(
|
|||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="text-[12px] font-[500] pr-[10px]">
|
||||
<div className="text-[12px] font-[500] pe-[10px]">
|
||||
{t('delete_post', 'Delete Post')}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -656,7 +656,7 @@ export const withProvider = function <T extends object>(
|
|||
/>
|
||||
)
|
||||
) : (
|
||||
<>No Content Yet</>
|
||||
<>{t('no_content_yet', 'No Content Yet')}</>
|
||||
)}
|
||||
</IntegrationContext.Provider>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import { ReactTags } from 'react-tag-autocomplete';
|
|||
import interClass from '@gitroom/react/helpers/inter.font';
|
||||
import { useIntegration } from '@gitroom/frontend/components/launches/helpers/use.integration';
|
||||
import clsx from 'clsx';
|
||||
import { useT } from '@gitroom/react/translation/get.transation.service.client';
|
||||
|
||||
export const InstagramCollaboratorsTags: FC<{
|
||||
name: string;
|
||||
label: string;
|
||||
|
|
@ -19,6 +21,8 @@ export const InstagramCollaboratorsTags: FC<{
|
|||
const { integration } = useIntegration();
|
||||
const [tagValue, setTagValue] = useState<any[]>([]);
|
||||
const [suggestions, setSuggestions] = useState<string>('');
|
||||
const t = useT();
|
||||
|
||||
const onDelete = useCallback(
|
||||
(tagIndex: number) => {
|
||||
const modify = tagValue.filter((_, i) => i !== tagIndex);
|
||||
|
|
@ -83,7 +87,7 @@ export const InstagramCollaboratorsTags: FC<{
|
|||
{label}
|
||||
</div>
|
||||
<ReactTags
|
||||
placeholderText="Add a tag"
|
||||
placeholderText={t('add_a_tag', 'Add a tag')}
|
||||
suggestions={suggestionsArray}
|
||||
selected={tagValue}
|
||||
onAdd={onAddition}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,12 @@ const LemmySettings: FC = () => {
|
|||
const deleteField = useCallback(
|
||||
(index: number) => async () => {
|
||||
if (
|
||||
!(await deleteDialog('Are you sure you want to delete this Subreddit?'))
|
||||
!(await deleteDialog(
|
||||
t(
|
||||
'are_you_sure_you_want_to_delete_this_subreddit',
|
||||
'Are you sure you want to delete this Subreddit?'
|
||||
)
|
||||
))
|
||||
)
|
||||
return;
|
||||
remove(index);
|
||||
|
|
@ -36,7 +41,7 @@ const LemmySettings: FC = () => {
|
|||
<div key={field.id} className="flex flex-col relative">
|
||||
<div
|
||||
onClick={deleteField(index)}
|
||||
className="absolute -left-[10px] justify-center items-center flex -top-[10px] w-[20px] h-[20px] bg-red-600 rounded-full text-textColor"
|
||||
className="absolute -start-[10px] justify-center items-center flex -top-[10px] w-[20px] h-[20px] bg-red-600 rounded-full text-textColor"
|
||||
>
|
||||
x
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
|||
import { useSettings } from '@gitroom/frontend/components/launches/helpers/use.values';
|
||||
import { ReactTags } from 'react-tag-autocomplete';
|
||||
import interClass from '@gitroom/react/helpers/inter.font';
|
||||
import { useT } from '@gitroom/react/translation/get.transation.service.client';
|
||||
|
||||
export const MediumTags: FC<{
|
||||
name: string;
|
||||
label: string;
|
||||
|
|
@ -16,6 +18,8 @@ export const MediumTags: FC<{
|
|||
const { getValues } = useSettings();
|
||||
const [tagValue, setTagValue] = useState<any[]>([]);
|
||||
const [suggestions, setSuggestions] = useState<string>('');
|
||||
const t = useT();
|
||||
|
||||
const onDelete = useCallback(
|
||||
(tagIndex: number) => {
|
||||
const modify = tagValue.filter((_, i) => i !== tagIndex);
|
||||
|
|
@ -64,7 +68,7 @@ export const MediumTags: FC<{
|
|||
<div>
|
||||
<div className={`${interClass} text-[14px] mb-[6px]`}>{label}</div>
|
||||
<ReactTags
|
||||
placeholderText="Add a tag"
|
||||
placeholderText={t('add_a_tag', 'Add a tag')}
|
||||
suggestions={suggestionsArray}
|
||||
selected={tagValue}
|
||||
onAdd={onAddition}
|
||||
|
|
|
|||
|
|
@ -131,10 +131,10 @@ const RedditPreview: FC = (props) => {
|
|||
height={24}
|
||||
src={`/icons/platforms/${integration?.identifier!}.png`}
|
||||
alt="x"
|
||||
className="rounded-full absolute -right-[5px] -bottom-[5px] z-[2]"
|
||||
className="rounded-full absolute -end-[5px] -bottom-[5px] z-[2]"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 flex flex-col leading-[16px] w-full pr-[64px] pb-[8px] rounded-[8px]">
|
||||
<div className="flex-1 flex flex-col leading-[16px] w-full pe-[64px] pb-[8px] rounded-[8px]">
|
||||
<div className="text-[14px] font-[600]">
|
||||
{integration?.name}
|
||||
</div>
|
||||
|
|
@ -171,7 +171,12 @@ const RedditSettings: FC = () => {
|
|||
const deleteField = useCallback(
|
||||
(index: number) => async () => {
|
||||
if (
|
||||
!(await deleteDialog('Are you sure you want to delete this Subreddit?'))
|
||||
!(await deleteDialog(
|
||||
t(
|
||||
'are_you_sure_you_want_to_delete_this_subreddit',
|
||||
'Are you sure you want to delete this Subreddit?'
|
||||
)
|
||||
))
|
||||
)
|
||||
return;
|
||||
remove(index);
|
||||
|
|
@ -185,7 +190,7 @@ const RedditSettings: FC = () => {
|
|||
<div key={field.id} className="flex flex-col relative">
|
||||
<div
|
||||
onClick={deleteField(index)}
|
||||
className="absolute -left-[10px] justify-center items-center flex -top-[10px] w-[20px] h-[20px] bg-red-600 rounded-full text-textColor"
|
||||
className="absolute -start-[10px] justify-center items-center flex -top-[10px] w-[20px] h-[20px] bg-red-600 rounded-full text-textColor"
|
||||
>
|
||||
x
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -14,44 +14,7 @@ import { useCustomProviderFunction } from '@gitroom/frontend/components/launches
|
|||
import { Checkbox } from '@gitroom/react/form/checkbox';
|
||||
import clsx from 'clsx';
|
||||
import { useT } from '@gitroom/react/translation/get.transation.service.client';
|
||||
const privacyLevel = [
|
||||
{
|
||||
value: 'PUBLIC_TO_EVERYONE',
|
||||
label: 'Public to everyone',
|
||||
},
|
||||
{
|
||||
value: 'MUTUAL_FOLLOW_FRIENDS',
|
||||
label: 'Mutual follow friends',
|
||||
},
|
||||
{
|
||||
value: 'FOLLOWER_OF_CREATOR',
|
||||
label: 'Follower of creator',
|
||||
},
|
||||
{
|
||||
value: 'SELF_ONLY',
|
||||
label: 'Self only',
|
||||
},
|
||||
];
|
||||
const contentPostingMethod = [
|
||||
{
|
||||
value: 'DIRECT_POST',
|
||||
label: 'Post content directly to TikTok',
|
||||
},
|
||||
{
|
||||
value: 'UPLOAD',
|
||||
label: 'Upload content to TikTok without posting it',
|
||||
},
|
||||
];
|
||||
const yesNo = [
|
||||
{
|
||||
value: 'yes',
|
||||
label: 'Yes',
|
||||
},
|
||||
{
|
||||
value: 'no',
|
||||
label: 'No',
|
||||
},
|
||||
];
|
||||
|
||||
const CheckTikTokValidity: FC<{
|
||||
picture: string;
|
||||
}> = (props) => {
|
||||
|
|
@ -125,11 +88,57 @@ const TikTokSettings: FC<{
|
|||
const brand_content_toggle = watch('brand_content_toggle');
|
||||
const content_posting_method = watch('content_posting_method');
|
||||
const isUploadMode = content_posting_method === 'UPLOAD';
|
||||
|
||||
const privacyLevel = [
|
||||
{
|
||||
value: 'PUBLIC_TO_EVERYONE',
|
||||
label: t('public_to_everyone', 'Public to everyone'),
|
||||
},
|
||||
{
|
||||
value: 'MUTUAL_FOLLOW_FRIENDS',
|
||||
label: t('mutual_follow_friends', 'Mutual follow friends'),
|
||||
},
|
||||
{
|
||||
value: 'FOLLOWER_OF_CREATOR',
|
||||
label: t('follower_of_creator', 'Follower of creator'),
|
||||
},
|
||||
{
|
||||
value: 'SELF_ONLY',
|
||||
label: t('self_only', 'Self only'),
|
||||
},
|
||||
];
|
||||
const contentPostingMethod = [
|
||||
{
|
||||
value: 'DIRECT_POST',
|
||||
label: t(
|
||||
'post_content_directly_to_tiktok',
|
||||
'Post content directly to TikTok'
|
||||
),
|
||||
},
|
||||
{
|
||||
value: 'UPLOAD',
|
||||
label: t(
|
||||
'upload_content_to_tiktok_without_posting',
|
||||
'Upload content to TikTok without posting it'
|
||||
),
|
||||
},
|
||||
];
|
||||
const yesNo = [
|
||||
{
|
||||
value: 'yes',
|
||||
label: t('yes', 'Yes'),
|
||||
},
|
||||
{
|
||||
value: 'no',
|
||||
label: t('no', 'No'),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<CheckTikTokValidity picture={props?.values?.[0]?.image?.[0]?.path} />
|
||||
<Select
|
||||
label="Who can see this video?"
|
||||
label={t('label_who_can_see_this_video', 'Who can see this video?')}
|
||||
hideErrors={true}
|
||||
disabled={isUploadMode}
|
||||
{...register('privacy_level', {
|
||||
|
|
@ -144,11 +153,14 @@ const TikTokSettings: FC<{
|
|||
))}
|
||||
</Select>
|
||||
<div className="text-[14px] mt-[10px] mb-[18px] text-balance">
|
||||
{`Choose upload without posting if you want to review and edit your content within TikTok's app before publishing.
|
||||
This gives you access to TikTok's built-in editing tools and lets you make final adjustments before posting.`}
|
||||
{t(
|
||||
'choose_upload_without_posting_description',
|
||||
`Choose upload without posting if you want to review and edit your content within TikTok's app before publishing.
|
||||
This gives you access to TikTok's built-in editing tools and lets you make final adjustments before posting.`
|
||||
)}
|
||||
</div>
|
||||
<Select
|
||||
label="Content posting method"
|
||||
label={t('label_content_posting_method', 'Content posting method')}
|
||||
disabled={isUploadMode}
|
||||
{...register('content_posting_method', {
|
||||
value: 'DIRECT_POST',
|
||||
|
|
@ -163,7 +175,7 @@ const TikTokSettings: FC<{
|
|||
</Select>
|
||||
<Select
|
||||
hideErrors={true}
|
||||
label="Auto add music"
|
||||
label={t('label_auto_add_music', 'Auto add music')}
|
||||
{...register('autoAddMusic', {
|
||||
value: 'no',
|
||||
})}
|
||||
|
|
@ -177,7 +189,7 @@ const TikTokSettings: FC<{
|
|||
</Select>
|
||||
<div className="text-[14px] mt-[10px] mb-[24px] text-balance">
|
||||
{t(
|
||||
'this_feature_available_only_for_photos_it_will_add_a_default_music_that_you_can_change_later',
|
||||
'this_feature_available_only_for_photos',
|
||||
'This feature available only for photos, it will add a default music that\n you can change later.'
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -188,14 +200,14 @@ const TikTokSettings: FC<{
|
|||
<div className="flex gap-[40px]">
|
||||
<Checkbox
|
||||
variant="hollow"
|
||||
label="Duet"
|
||||
label={t('label_duet', 'Duet')}
|
||||
disabled={isUploadMode}
|
||||
{...register('duet', {
|
||||
value: false,
|
||||
})}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Stitch"
|
||||
label={t('label_stitch', 'Stitch')}
|
||||
variant="hollow"
|
||||
disabled={isUploadMode}
|
||||
{...register('stitch', {
|
||||
|
|
@ -203,7 +215,7 @@ const TikTokSettings: FC<{
|
|||
})}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Comments"
|
||||
label={t('label_comments', 'Comments')}
|
||||
variant="hollow"
|
||||
disabled={isUploadMode}
|
||||
{...register('comment', {
|
||||
|
|
@ -215,7 +227,7 @@ const TikTokSettings: FC<{
|
|||
<div className="flex flex-col">
|
||||
<Checkbox
|
||||
variant="hollow"
|
||||
label="Disclose Video Content"
|
||||
label={t('label_disclose_video_content', 'Disclose Video Content')}
|
||||
disabled={isUploadMode}
|
||||
{...register('disclose', {
|
||||
value: false,
|
||||
|
|
@ -239,12 +251,12 @@ const TikTokSettings: FC<{
|
|||
</div>
|
||||
<div>
|
||||
{t(
|
||||
'your_video_will_be_labeled_promotional_content',
|
||||
'your_video_will_be_labeled_promotional',
|
||||
'Your video will be labeled "Promotional Content".'
|
||||
)}
|
||||
<br />
|
||||
{t(
|
||||
'this_cannot_be_changed_once_your_video_is_posted',
|
||||
'this_cannot_be_changed_once_posted',
|
||||
'This cannot be changed once your video is posted.'
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -252,7 +264,7 @@ const TikTokSettings: FC<{
|
|||
)}
|
||||
<div className="text-[14px] my-[10px] text-balance">
|
||||
{t(
|
||||
'turn_on_to_disclose_that_this_video_promotes_goods_or_services',
|
||||
'turn_on_to_disclose_video_promotes',
|
||||
'Turn on to disclose that this video promotes goods or services in\n exchange for something of value. You video could promote yourself, a\n third party, or both.'
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -260,7 +272,7 @@ const TikTokSettings: FC<{
|
|||
<div className={clsx(!disclose && 'invisible', 'mt-[20px]')}>
|
||||
<Checkbox
|
||||
variant="hollow"
|
||||
label="Your brand"
|
||||
label={t('label_your_brand', 'Your brand')}
|
||||
disabled={isUploadMode}
|
||||
{...register('brand_organic_toggle', {
|
||||
value: false,
|
||||
|
|
@ -268,18 +280,18 @@ const TikTokSettings: FC<{
|
|||
/>
|
||||
<div className="text-balance my-[10px] text-[14px]">
|
||||
{t(
|
||||
'you_are_promoting_yourself_or_your_own_brand',
|
||||
'you_are_promoting_yourself',
|
||||
'You are promoting yourself or your own brand.'
|
||||
)}
|
||||
<br />
|
||||
{t(
|
||||
'this_video_will_be_classified_as_brand_organic',
|
||||
'this_video_will_be_classified_brand_organic',
|
||||
'This video will be classified as Brand Organic.'
|
||||
)}
|
||||
</div>
|
||||
<Checkbox
|
||||
variant="hollow"
|
||||
label="Branded content"
|
||||
label={t('label_branded_content', 'Branded content')}
|
||||
disabled={isUploadMode}
|
||||
{...register('brand_content_toggle', {
|
||||
value: false,
|
||||
|
|
@ -287,19 +299,19 @@ const TikTokSettings: FC<{
|
|||
/>
|
||||
<div className="text-balance my-[10px] text-[14px]">
|
||||
{t(
|
||||
'you_are_promoting_another_brand_or_a_third_party',
|
||||
'you_are_promoting_another_brand',
|
||||
'You are promoting another brand or a third party.'
|
||||
)}
|
||||
<br />
|
||||
{t(
|
||||
'this_video_will_be_classified_as_branded_content',
|
||||
'this_video_will_be_classified_branded_content',
|
||||
'This video will be classified as Branded Content.'
|
||||
)}
|
||||
</div>
|
||||
{(brand_organic_toggle || brand_content_toggle) && (
|
||||
<div className="my-[10px] text-[14px] text-balance">
|
||||
{t(
|
||||
'by_posting_you_agree_to_tiktok_s',
|
||||
'by_posting_you_agree_to_tiktoks',
|
||||
"By posting, you agree to TikTok's"
|
||||
)}
|
||||
{[
|
||||
|
|
@ -312,7 +324,7 @@ const TikTokSettings: FC<{
|
|||
{t('music_usage_confirmation', 'Music Usage Confirmation')}
|
||||
</a>
|
||||
) : undefined,
|
||||
brand_content_toggle ? <> and </> : undefined,
|
||||
brand_content_toggle ? <> {t('and', 'and')} </> : undefined,
|
||||
brand_content_toggle ? (
|
||||
<a
|
||||
target="_blank"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,12 @@ const WrapcastProvider: FC = () => {
|
|||
const deleteField = useCallback(
|
||||
(index: number) => async () => {
|
||||
if (
|
||||
!(await deleteDialog('Are you sure you want to delete this Subreddit?'))
|
||||
!(await deleteDialog(
|
||||
t(
|
||||
'are_you_sure_you_want_to_delete_this_subreddit',
|
||||
'Are you sure you want to delete this Subreddit?'
|
||||
)
|
||||
))
|
||||
)
|
||||
return;
|
||||
remove(index);
|
||||
|
|
@ -35,7 +40,7 @@ const WrapcastProvider: FC = () => {
|
|||
<div key={field.id} className="flex flex-col relative">
|
||||
<div
|
||||
onClick={deleteField(index)}
|
||||
className="absolute -left-[10px] justify-center items-center flex -top-[10px] w-[20px] h-[20px] bg-red-600 rounded-full text-textColor"
|
||||
className="absolute -start-[10px] justify-center items-center flex -top-[10px] w-[20px] h-[20px] bg-red-600 rounded-full text-textColor"
|
||||
>
|
||||
x
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ export const SettingsModal: FC<{
|
|||
<div className="rounded-[4px] border border-customColor6 bg-sixth px-[16px] pb-[16px] relative w-full">
|
||||
<TopTitle title={`Additional Settings`} />
|
||||
<button
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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()}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export const StatisticsModal: FC<{
|
|||
<div className="bg-sixth p-[32px] w-full max-w-[920px] mx-auto flex flex-col rounded-[4px] border border-customColor6 relative">
|
||||
<button
|
||||
onClick={closeAll}
|
||||
className="outline-none absolute right-[20px] top-[15px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ export const TagsComponent: FC<{
|
|||
{showModal && <ShowModal {...showModal} />}
|
||||
<div className="flex-1 flex tags-top">
|
||||
<ReactTags
|
||||
placeholderText="Add a tag"
|
||||
placeholderText={t('add_a_tag', 'Add a tag')}
|
||||
suggestions={suggestionsArray}
|
||||
selected={tagValue}
|
||||
onAdd={onAddition}
|
||||
|
|
@ -171,19 +171,19 @@ export const TagsComponent: FC<{
|
|||
);
|
||||
return (
|
||||
<div
|
||||
className={`min-w-[50px] float-left ml-[4px] p-[3px] rounded-sm relative`}
|
||||
className={`min-w-[50px] float-left ms-[4px] p-[3px] rounded-sm relative`}
|
||||
style={{
|
||||
backgroundColor: findTag?.color,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="absolute -top-[5px] left-[10px] text-[12px] text-red-600 bg-white px-[3px] rounded-full"
|
||||
className="absolute -top-[5px] start-[10px] text-[12px] text-red-600 bg-white px-[3px] rounded-full"
|
||||
onClick={edit(findTag)}
|
||||
>
|
||||
{t('edit', 'Edit')}
|
||||
</div>
|
||||
<div
|
||||
className="absolute -top-[5px] -left-[5px] text-[12px] text-red-600 bg-white px-[3px] rounded-full"
|
||||
className="absolute -top-[5px] -start-[5px] text-[12px] text-red-600 bg-white px-[3px] rounded-full"
|
||||
onClick={() => onDelete(findIndex)}
|
||||
>
|
||||
X
|
||||
|
|
@ -223,11 +223,11 @@ const ShowModal: FC<{
|
|||
resolve(tagName);
|
||||
}, [tagName, color, id]);
|
||||
return (
|
||||
<div className="bg-black/40 fixed left-0 top-0 w-full h-full z-[500]">
|
||||
<div className="bg-black/40 fixed start-0 top-0 w-full h-full z-[500]">
|
||||
<div className="relative w-[500px] mx-auto flex gap-[20px] flex-col flex-1 rounded-[4px] border border-customColor6 bg-sixth p-[16px] pt-0">
|
||||
<TopTitle title={`Create a new tag`} />
|
||||
<button
|
||||
className="outline-none absolute right-[20px] top-[15px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
|
|||
|
|
@ -40,8 +40,11 @@ export const TimeTable: FC<{
|
|||
const askClose = useCallback(async () => {
|
||||
if (
|
||||
!(await deleteDialog(
|
||||
'Are you sure you want to close the window?',
|
||||
'Yes, close'
|
||||
t(
|
||||
'are_you_sure_you_want_to_close_the_window',
|
||||
'Are you sure you want to close the window?'
|
||||
),
|
||||
t('yes_close', 'Yes, close')
|
||||
))
|
||||
) {
|
||||
return;
|
||||
|
|
@ -51,7 +54,14 @@ export const TimeTable: FC<{
|
|||
useKeypress('Escape', askClose);
|
||||
const removeSlot = useCallback(
|
||||
(index: number) => async () => {
|
||||
if (!(await deleteDialog('Are you sure you want to delete this slot?'))) {
|
||||
if (
|
||||
!(await deleteDialog(
|
||||
t(
|
||||
'are_you_sure_you_want_to_delete_this_slot',
|
||||
'Are you sure you want to delete this slot?'
|
||||
)
|
||||
))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
setCurrentTimes((prev) => prev.filter((_, i) => i !== index));
|
||||
|
|
@ -102,7 +112,7 @@ export const TimeTable: FC<{
|
|||
<TopTitle title={`Time Table Slots`} />
|
||||
<button
|
||||
onClick={askClose}
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
@ -172,9 +182,9 @@ export const TimeTable: FC<{
|
|||
<div className="mt-[16px] grid grid-cols-2 place-items-center w-[100px] mx-auto">
|
||||
{times.map((timeSlot, index) => (
|
||||
<Fragment key={timeSlot.formatted}>
|
||||
<div className="text-left w-full">{timeSlot.formatted}</div>
|
||||
<div className="text-start w-full">{timeSlot.formatted}</div>
|
||||
<div
|
||||
className="cursor-pointer text-red-400 text-left w-full"
|
||||
className="cursor-pointer text-red-400 text-start w-full"
|
||||
onClick={removeSlot(index)}
|
||||
>
|
||||
X
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export const WrapcasterProvider: FC<Web3ProviderInterface> = (props) => {
|
|||
<div className="rounded-[4px] border border-customColor6 bg-sixth px-[16px] pb-[16px] relative w-full">
|
||||
<TopTitle title={`Add Wrapcast`} />
|
||||
<button
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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()}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ export const TelegramProvider: FC<Web3ProviderInterface> = (props) => {
|
|||
<div className="rounded-[4px] border border-customColor6 bg-sixth px-[16px] pb-[16px] relative w-[700px]">
|
||||
<TopTitle title={`Add Telegram`} />
|
||||
<button
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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()}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export const WrapcasterProvider: FC<Web3ProviderInterface> = (props) => {
|
|||
<div className="rounded-[4px] border border-customColor6 bg-sixth px-[16px] pb-[16px] relative w-full">
|
||||
<TopTitle title={`Add Wrapcast`} />
|
||||
<button
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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()}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export const ChromeExtensionComponent = () => {
|
|||
viewBox="0 0 32 32"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="mr-2"
|
||||
className="me-2"
|
||||
>
|
||||
<path
|
||||
d="M16 3.5C13.5277 3.5 11.111 4.23311 9.05538 5.60663C6.99976 6.98015 5.39761 8.93238 4.45151 11.2165C3.50542 13.5005 3.25787 16.0139 3.74019 18.4386C4.2225 20.8634 5.41301 23.0907 7.16117 24.8388C8.90933 26.587 11.1366 27.7775 13.5614 28.2598C15.9861 28.7421 18.4995 28.4946 20.7835 27.5485C23.0676 26.6024 25.0199 25.0002 26.3934 22.9446C27.7669 20.889 28.5 18.4723 28.5 16C28.4964 12.6859 27.1782 9.5086 24.8348 7.16518C22.4914 4.82177 19.3141 3.50364 16 3.5ZM16 4.5C18.0667 4.50143 20.095 5.0593 21.8717 6.11505C23.6484 7.1708 25.1081 8.68547 26.0975 10.5H16C14.6261 10.5017 13.3024 11.0169 12.2889 11.9446C11.2754 12.8723 10.6454 14.1453 10.5225 15.5138L6.81376 9.09C7.88392 7.66472 9.27106 6.50801 10.8654 5.71137C12.4598 4.91472 14.2177 4.5 16 4.5ZM16 20.5C15.11 20.5 14.24 20.2361 13.4999 19.7416C12.7599 19.2471 12.1831 18.5443 11.8425 17.7221C11.502 16.8998 11.4128 15.995 11.5865 15.1221C11.7601 14.2492 12.1887 13.4474 12.818 12.818C13.4474 12.1887 14.2492 11.7601 15.1221 11.5865C15.995 11.4128 16.8998 11.5019 17.7221 11.8425C18.5443 12.1831 19.2472 12.7599 19.7416 13.4999C20.2361 14.24 20.5 15.11 20.5 16C20.5 17.1935 20.0259 18.3381 19.182 19.182C18.3381 20.0259 17.1935 20.5 16 20.5ZM4.50001 16C4.49787 13.8844 5.08245 11.8096 6.18876 10.0063L11.2375 18.75C11.2375 18.7612 11.2513 18.7712 11.2588 18.7825C11.9496 19.9629 13.056 20.843 14.3616 21.2506C15.6671 21.6582 17.0778 21.564 18.3175 20.9862L14.605 27.415C11.8188 27.071 9.25413 25.721 7.39328 23.6189C5.53243 21.5168 4.50353 18.8074 4.50001 16ZM16 27.5C15.9038 27.5 15.8088 27.5 15.7138 27.5L20.7625 18.75C20.767 18.742 20.7708 18.7337 20.7738 18.725C21.455 17.5362 21.6668 16.1356 21.3675 14.7985C21.0682 13.4615 20.2794 12.2848 19.1563 11.5H26.5825C27.3261 13.2487 27.6247 15.1544 27.4518 17.0468C27.2788 18.9391 26.6396 20.7591 25.5913 22.3441C24.543 23.929 23.1183 25.2295 21.4446 26.1292C19.7709 27.029 17.9002 27.4999 16 27.5Z"
|
||||
|
|
|
|||
|
|
@ -44,18 +44,18 @@ export const ContinueProvider: FC = () => {
|
|||
}
|
||||
return (
|
||||
<div
|
||||
className="fixed left-0 top-0 w-full h-full bg-primary/40 z-[499]"
|
||||
className="fixed start-0 top-0 w-full h-full bg-primary/40 z-[499]"
|
||||
onClick={closeModal}
|
||||
>
|
||||
<div
|
||||
className="w-[100%] max-w-[674px] absolute left-[50%] top-[65px] bg-customColor3 z-[500] -translate-x-[50%] text-textColor p-[16px] !pt-0 border border-customColor6 min-h-[300px]"
|
||||
className="w-[100%] max-w-[674px] absolute start-[50%] top-[65px] bg-customColor3 z-[500] -translate-x-[50%] text-textColor p-[16px] !pt-0 border border-customColor6 min-h-[300px]"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="w-full h-full relative">
|
||||
<TopTitle title="Configure Provider" />
|
||||
<button
|
||||
onClick={closeModal}
|
||||
className="outline-none absolute right-0 top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
className="outline-none absolute end-0 top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export const DropFiles: FC<{
|
|||
return (
|
||||
<div {...getRootProps()} className="relative">
|
||||
{isDragActive && (
|
||||
<div className="absolute left-0 top-0 w-full h-full bg-black/90 flex items-center justify-center z-[200] animate-normalFadeIn">
|
||||
<div className="absolute start-0 top-0 w-full h-full bg-black/90 flex items-center justify-center z-[200] animate-normalFadeIn">
|
||||
{t('drag_n_drop_some_files_here', 'Drag n drop some files here')}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
'use client';
|
||||
import { FC, ReactNode, useEffect, useState } from 'react';
|
||||
import i18next from '@gitroom/react/translation/i18next';
|
||||
|
||||
export const HtmlComponent: FC<{ className: string; children: ReactNode }> = (
|
||||
props
|
||||
) => {
|
||||
const { className } = props;
|
||||
const [dir, setDir] = useState(i18next.dir());
|
||||
useEffect(() => {
|
||||
i18next.on('languageChanged', (lng) => {
|
||||
setDir(i18next.dir());
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<html className={className} dir={dir}>
|
||||
{props.children}
|
||||
</html>
|
||||
);
|
||||
};
|
||||
|
|
@ -150,10 +150,10 @@ export const Impersonate = () => {
|
|||
{!!data?.length && (
|
||||
<>
|
||||
<div
|
||||
className="bg-primary/80 fixed left-0 top-0 w-full h-full z-[998]"
|
||||
className="bg-primary/80 fixed start-0 top-0 w-full h-full z-[998]"
|
||||
onClick={() => setName('')}
|
||||
/>
|
||||
<div className="absolute top-[100%] w-full left-0 bg-sixth border border-customColor6 text-textColor z-[999]">
|
||||
<div className="absolute top-[100%] w-full start-0 bg-sixth border border-customColor6 text-textColor z-[999]">
|
||||
{mapData?.map((user: any) => (
|
||||
<div
|
||||
onClick={setUser(user.id)}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export const ChangeLanguageComponent = () => {
|
|||
const [_, setCookie] = useCookie(cookieName, currentLanguage || fallbackLng);
|
||||
const handleLanguageChange = (language: string) => {
|
||||
setCookie(language);
|
||||
window.location.reload();
|
||||
i18next.changeLanguage(language);
|
||||
};
|
||||
|
||||
// Function to get language name in its native script
|
||||
|
|
@ -137,7 +137,7 @@ export const LanguageComponent = () => {
|
|||
viewBox="0 0 32 32"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="mr-2 cursor-pointer"
|
||||
className="me-2 cursor-pointer"
|
||||
onClick={openModal}
|
||||
>
|
||||
<path
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import { CheckPayment } from '@gitroom/frontend/components/layout/check.payment'
|
|||
import { ChromeExtensionComponent } from '@gitroom/frontend/components/layout/chrome.extension.component';
|
||||
import { LanguageComponent } from '@gitroom/frontend/components/layout/language.component';
|
||||
import { useT } from '@gitroom/react/translation/get.transation.service.client';
|
||||
import i18next from '@gitroom/react/translation/i18next';
|
||||
extend(utc);
|
||||
extend(weekOfYear);
|
||||
extend(isoWeek);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,15 @@ export const LogoutComponent = () => {
|
|||
const t = useT();
|
||||
|
||||
const logout = useCallback(async () => {
|
||||
if (await deleteDialog('Are you sure you want to logout?', 'Yes logout')) {
|
||||
if (
|
||||
await deleteDialog(
|
||||
t(
|
||||
'are_you_sure_you_want_to_logout',
|
||||
'Are you sure you want to logout?'
|
||||
),
|
||||
t('yes_logout', 'Yes logout')
|
||||
)
|
||||
) {
|
||||
if (!isSecured) {
|
||||
setCookie('auth', '', -10);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ export const OrganizationSelector = () => {
|
|||
)}
|
||||
</div>
|
||||
{data?.length > 1 && (
|
||||
<div className="hidden py-[12px] px-[12px] group-hover:flex w-full absolute top-[100%] left-0 bg-third border-tableBorder border-x border-b gap-[12px] cursor-pointer flex-col">
|
||||
<div className="hidden py-[12px] px-[12px] group-hover:flex w-full absolute top-[100%] start-0 bg-third border-tableBorder border-x border-b gap-[12px] cursor-pointer flex-col">
|
||||
{withoutCurrent?.map((org: { name: string; id: string }) => (
|
||||
<div key={org.id} onClick={changeOrg(org)}>
|
||||
{org.name}
|
||||
|
|
|
|||
|
|
@ -81,11 +81,14 @@ export const SettingsPopup: FC<{
|
|||
if (user?.tier?.webhooks) {
|
||||
return 'webhooks';
|
||||
}
|
||||
if (user?.tier?.autoPost) {
|
||||
return 'autopost';
|
||||
}
|
||||
if (user?.tier?.public_api && isGeneral) {
|
||||
return 'api';
|
||||
}
|
||||
return 'teams';
|
||||
}, []);
|
||||
return 'signatures';
|
||||
}, [user?.tier, isGeneral]);
|
||||
|
||||
const t = useT();
|
||||
|
||||
|
|
@ -146,7 +149,7 @@ export const SettingsPopup: FC<{
|
|||
<div className="rounded-[4px] border border-customColor6 p-[24px] flex flex-col">
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="w-[455px]">
|
||||
<Input label="Full Name" name="fullname" />
|
||||
<Input label="Full Name" translationKey="label_full_name" name="fullname" />
|
||||
</div>
|
||||
<div className="flex gap-[8px] mb-[10px]">
|
||||
<div className="w-[48px] h-[48px] rounded-full bg-customColor38">
|
||||
|
|
@ -213,7 +216,7 @@ export const SettingsPopup: FC<{
|
|||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Textarea label="Bio" name="bio" className="resize-none" />
|
||||
<Textarea label="Bio" translationKey="label_bio" name="bio" className="resize-none" />
|
||||
</div>
|
||||
</div>
|
||||
</Tabs.Panel> */}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export const Support = () => {
|
|||
if (!discordUrl || !show) return null;
|
||||
return (
|
||||
<div
|
||||
className="bg-customColor39 w-[194px] h-[58px] fixed right-[20px] bottom-[20px] z-[500] text-[16px] text-customColor40 rounded-[30px] !rounded-br-[0] cursor-pointer flex justify-center items-center gap-[10px]"
|
||||
className="bg-customColor39 w-[194px] h-[58px] fixed end-[20px] bottom-[20px] z-[500] text-[16px] text-customColor40 rounded-[30px] !rounded-br-[0] cursor-pointer flex justify-center items-center gap-[10px]"
|
||||
onClick={() => window.open(discordUrl)}
|
||||
>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export const BuyerSeller: FC = () => {
|
|||
const pathComputed = path === '/marketplace' ? '/marketplace/seller' : path;
|
||||
return (
|
||||
<div className="relative">
|
||||
<div className="w-[286px] h-[50px] bg-third p-[9px] flex select-none absolute -translate-y-[63px] right-0">
|
||||
<div className="w-[286px] h-[50px] bg-third p-[9px] flex select-none absolute -translate-y-[63px] end-0">
|
||||
<div className="bg-input flex flex-1">
|
||||
<Link
|
||||
href="/marketplace/seller"
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ const Pagination: FC<{
|
|||
}
|
||||
return (
|
||||
<div className="flex items-center relative">
|
||||
<div className="absolute left-0">
|
||||
<div className="absolute start-0">
|
||||
{t('showing', 'Showing')}
|
||||
{from + 1}
|
||||
{t('to', 'to')}
|
||||
|
|
@ -322,7 +322,7 @@ export const RequestService: FC<{
|
|||
<div className="w-full max-w-[920px] mx-auto bg-sixth px-[16px] rounded-[4px] border border-customColor6 gap-[24px] flex flex-col relative">
|
||||
<button
|
||||
onClick={close}
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
@ -407,7 +407,7 @@ export const Card: FC<{
|
|||
className="rounded-full w-full h-full"
|
||||
/>
|
||||
)}
|
||||
<div className="w-[80px] h-[28px] bg-customColor4 absolute bottom-0 left-[50%] -translate-x-[50%] rounded-[30px] flex gap-[4px] justify-center items-center">
|
||||
<div className="w-[80px] h-[28px] bg-customColor4 absolute bottom-0 start-[50%] -translate-x-[50%] rounded-[30px] flex gap-[4px] justify-center items-center">
|
||||
<div>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
|
@ -483,7 +483,7 @@ export const Card: FC<{
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="ml-[100px] items-center flex">
|
||||
<div className="ms-[100px] items-center flex">
|
||||
<Button onClick={requestService}>
|
||||
{t('request_service', 'Request Service')}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export const OrderList: FC<{
|
|||
className="w-[24px] h-[24px] rounded-full"
|
||||
/>
|
||||
<img
|
||||
className="absolute left-[15px] top-[15px] w-[15px] h-[15px] rounded-full"
|
||||
className="absolute start-[15px] top-[15px] w-[15px] h-[15px] rounded-full"
|
||||
src={`/icons/platforms/${details.integration.providerIdentifier}.png`}
|
||||
alt={details.integration.name}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ export const NewOrder: FC<{
|
|||
alt={p.name}
|
||||
/>
|
||||
<img
|
||||
className="absolute left-[10px] top-[10px] w-[15px] h-[15px] rounded-full"
|
||||
className="absolute start-[10px] top-[10px] w-[15px] h-[15px] rounded-full"
|
||||
src={`/icons/platforms/${p.identifier}.png`}
|
||||
alt={p.name}
|
||||
/>
|
||||
|
|
@ -170,7 +170,7 @@ export const NewOrder: FC<{
|
|||
<div className="w-full max-w-[647px] mx-auto bg-sixth px-[16px] rounded-[4px] border border-customColor6 gap-[24px] flex flex-col relative">
|
||||
<button
|
||||
onClick={close}
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
@ -196,7 +196,7 @@ export const NewOrder: FC<{
|
|||
{index !== 0 && (
|
||||
<div
|
||||
onClick={() => remove(index)}
|
||||
className="cursor-pointer top-[3px] z-[99] w-[15px] h-[15px] bg-red-500 rounded-full text-textColor absolute left-[60px] text-[12px] flex justify-center items-center pb-[2px] select-none"
|
||||
className="cursor-pointer top-[3px] z-[99] w-[15px] h-[15px] bg-red-500 rounded-full text-textColor absolute start-[60px] text-[12px] flex justify-center items-center pb-[2px] select-none"
|
||||
>
|
||||
x
|
||||
</div>
|
||||
|
|
@ -208,6 +208,7 @@ export const NewOrder: FC<{
|
|||
options={possibleOptions[index]}
|
||||
placeholder="Select social media"
|
||||
label="Platform"
|
||||
translationKey="label_platform"
|
||||
disableForm={true}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -222,6 +223,7 @@ export const NewOrder: FC<{
|
|||
icon={<div className="text-[14px]">$</div>}
|
||||
className="text-[14px]"
|
||||
label="Price per post"
|
||||
translationKey="label_price_per_post"
|
||||
error={
|
||||
form.formState.errors?.socialMedia?.[index]?.price
|
||||
?.message
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ export const Published: FC<{
|
|||
className="w-[24px] h-[24px] rounded-full"
|
||||
/>
|
||||
<img
|
||||
className="absolute left-[15px] top-[15px] w-[15px] h-[15px] rounded-full"
|
||||
className="absolute start-[15px] top-[15px] w-[15px] h-[15px] rounded-full"
|
||||
src={`/icons/platforms/${data.data.integration}.png`}
|
||||
alt={data.data.name}
|
||||
/>
|
||||
|
|
@ -103,7 +103,7 @@ export const PreviewPopup: FC<{
|
|||
<div className="bg-primary p-[20px] w-full relative">
|
||||
<button
|
||||
onClick={close}
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
@ -171,7 +171,7 @@ export const Offer: FC<{
|
|||
className="w-[24px] h-[24px] rounded-full"
|
||||
/>
|
||||
<img
|
||||
className="absolute left-[15px] top-[15px] w-[15px] h-[15px] rounded-full"
|
||||
className="absolute start-[15px] top-[15px] w-[15px] h-[15px] rounded-full"
|
||||
src={`/icons/platforms/${item.integration.providerIdentifier}.png`}
|
||||
alt={item.integration.name}
|
||||
/>
|
||||
|
|
@ -319,7 +319,7 @@ export const Post: FC<{
|
|||
className="w-[24px] h-[24px] rounded-full"
|
||||
/>
|
||||
<img
|
||||
className="absolute left-[15px] top-[15px] w-[15px] h-[15px] rounded-full"
|
||||
className="absolute start-[15px] top-[15px] w-[15px] h-[15px] rounded-full"
|
||||
src={`/icons/platforms/${integrationData?.providerIdentifier}.png`}
|
||||
alt={integrationData?.name}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export const Pagination: FC<{
|
|||
<ul className="flex flex-row items-center gap-1 justify-center mt-[15px]">
|
||||
<li className={clsx(current === 0 && 'opacity-20 pointer-events-none')}>
|
||||
<div
|
||||
className="cursor-pointer inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 h-10 px-4 py-2 gap-1 pl-2.5 text-gray-400 hover:text-white border-[#1F1F1F] hover:bg-forth"
|
||||
className="cursor-pointer inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 h-10 px-4 py-2 gap-1 ps-2.5 text-gray-400 hover:text-white border-[#1F1F1F] hover:bg-forth"
|
||||
aria-label="Go to previous page"
|
||||
onClick={() => setPage(current - 1)}
|
||||
>
|
||||
|
|
@ -95,7 +95,7 @@ export const Pagination: FC<{
|
|||
)}
|
||||
>
|
||||
<a
|
||||
className="text-textColor hover:text-white group cursor-pointer inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 h-10 px-4 py-2 gap-1 pr-2.5 text-gray-400 border-[#1F1F1F] hover:bg-forth"
|
||||
className="text-textColor hover:text-white group cursor-pointer inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 h-10 px-4 py-2 gap-1 pe-2.5 text-gray-400 border-[#1F1F1F] hover:bg-forth"
|
||||
aria-label="Go to next page"
|
||||
onClick={() => setPage(current + 1)}
|
||||
>
|
||||
|
|
@ -261,7 +261,14 @@ export const MediaBox: FC<{
|
|||
const removeItem = useCallback(
|
||||
(media: Media) => async (e: any) => {
|
||||
e.stopPropagation();
|
||||
if (!(await deleteDialog('Are you sure you want to delete the image?'))) {
|
||||
if (
|
||||
!(await deleteDialog(
|
||||
t(
|
||||
'are_you_sure_you_want_to_delete_the_image',
|
||||
'Are you sure you want to delete the image?'
|
||||
)
|
||||
))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
await fetch(`/media/${media.id}`, {
|
||||
|
|
@ -283,7 +290,7 @@ export const MediaBox: FC<{
|
|||
const t = useT();
|
||||
|
||||
return (
|
||||
<div className="removeEditor fixed left-0 top-0 bg-primary/80 z-[300] w-full min-h-full p-4 md:p-[60px] animate-fade">
|
||||
<div className="removeEditor fixed start-0 top-0 bg-primary/80 z-[300] w-full min-h-full p-4 md:p-[60px] animate-fade">
|
||||
<div className="max-w-[1000px] w-full h-full bg-sixth border-tableBorder border-2 rounded-xl relative mx-auto">
|
||||
<DropFiles onDrop={dragAndDrop}>
|
||||
<div className="pb-[20px] px-[20px] w-full h-full">
|
||||
|
|
@ -293,7 +300,7 @@ export const MediaBox: FC<{
|
|||
</div>
|
||||
<button
|
||||
onClick={closeModal}
|
||||
className="outline-none z-[300] absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root bg-primary hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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"
|
||||
>
|
||||
<svg
|
||||
|
|
@ -312,7 +319,7 @@ export const MediaBox: FC<{
|
|||
</svg>
|
||||
</button>
|
||||
|
||||
<div className="absolute flex justify-center mt-[55px] items-center pointer-events-none text-center h-[57px] w-full left-0 rounded-lg transition-all group text-sm font-semibold bg-transparent text-gray-800 hover:bg-gray-100 focus:text-primary-500">
|
||||
<div className="absolute flex justify-center mt-[55px] items-center pointer-events-none text-center h-[57px] w-full start-0 rounded-lg transition-all group text-sm font-semibold bg-transparent text-gray-800 hover:bg-gray-100 focus:text-primary-500">
|
||||
{t(
|
||||
'select_or_upload_pictures_maximum_5_at_a_time',
|
||||
'Select or upload pictures (maximum 5 at a time)'
|
||||
|
|
@ -326,8 +333,8 @@ export const MediaBox: FC<{
|
|||
|
||||
{!!mediaList.length && (
|
||||
<>
|
||||
<div className="flex absolute h-[57px] w-full left-0 top-0 rounded-lg transition-all group text-sm font-semibold bg-transparent text-gray-800 hover:bg-gray-100 focus:text-primary-500">
|
||||
<div className="relative flex flex-1 pr-[45px] gap-2 items-center justify-center">
|
||||
<div className="flex absolute h-[57px] w-full start-0 top-0 rounded-lg transition-all group text-sm font-semibold bg-transparent text-gray-800 hover:bg-gray-100 focus:text-primary-500">
|
||||
<div className="relative flex flex-1 pe-[45px] gap-2 items-center justify-center">
|
||||
<div className="flex-1" />
|
||||
<MultipartFileUploader
|
||||
uppRef={ref}
|
||||
|
|
@ -414,7 +421,7 @@ export const MediaBox: FC<{
|
|||
>
|
||||
<div
|
||||
onClick={removeItem(media)}
|
||||
className="border border-red-400 !text-white flex justify-center items-center absolute w-[20px] h-[20px] rounded-full bg-red-700 -top-[5px] -right-[5px]"
|
||||
className="border border-red-400 !text-white flex justify-center items-center absolute w-[20px] h-[20px] rounded-full bg-red-700 -top-[5px] -end-[5px]"
|
||||
>
|
||||
X
|
||||
</div>
|
||||
|
|
@ -542,7 +549,7 @@ export const MultiMediaComponent: FC<{
|
|||
<div className="flex">
|
||||
<Button
|
||||
onClick={showModal}
|
||||
className="ml-[10px] rounded-[4px] mb-[10px] gap-[8px] !text-primary justify-center items-center w-[127px] flex border border-dashed border-customColor21 bg-input"
|
||||
className="ms-[10px] rounded-[4px] mb-[10px] 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>
|
||||
|
|
@ -568,7 +575,7 @@ export const MultiMediaComponent: FC<{
|
|||
|
||||
<Button
|
||||
onClick={designMedia}
|
||||
className="ml-[10px] rounded-[4px] mb-[10px] gap-[8px] !text-primary justify-center items-center w-[127px] flex border border-dashed border-customColor21 bg-input"
|
||||
className="ms-[10px] rounded-[4px] mb-[10px] 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>
|
||||
|
|
@ -615,7 +622,7 @@ export const MultiMediaComponent: FC<{
|
|||
</div>
|
||||
<div
|
||||
onClick={clearMedia(index)}
|
||||
className="rounded-full w-[15px] h-[15px] bg-red-800 text-textColor flex justify-center items-center absolute -right-[4px] -top-[4px]"
|
||||
className="rounded-full w-[15px] h-[15px] bg-red-800 text-textColor flex justify-center items-center absolute -end-[4px] -top-[4px]"
|
||||
>
|
||||
x
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import '@uppy/core/dist/style.min.css';
|
|||
import '@uppy/dashboard/dist/style.min.css';
|
||||
import { useVariables } from '@gitroom/react/helpers/variable.context';
|
||||
import Compressor from '@uppy/compressor';
|
||||
import { useT } from '@gitroom/react/translation/get.transation.service.client';
|
||||
|
||||
export function MultipartFileUploader({
|
||||
onUploadSuccess,
|
||||
allowedFileTypes,
|
||||
|
|
@ -117,6 +119,7 @@ export function MultipartFileUploaderAfter({
|
|||
allowedFileTypes: string;
|
||||
uppRef: any;
|
||||
}) {
|
||||
const t = useT();
|
||||
const uppy = useUppyUploader({
|
||||
onUploadSuccess,
|
||||
allowedFileTypes,
|
||||
|
|
@ -135,7 +138,7 @@ export function MultipartFileUploaderAfter({
|
|||
uppy={uppyInstance}
|
||||
locale={{
|
||||
strings: {
|
||||
chooseFiles: 'Upload',
|
||||
chooseFiles: t('upload', 'Upload'),
|
||||
},
|
||||
// @ts-ignore
|
||||
pluralize: (n: any) => n,
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ const Card: FC<{
|
|||
)}
|
||||
</div>
|
||||
<div className="flex-1 relative">
|
||||
<div className="absolute left-0 top-0 w-full h-full flex flex-col whitespace-nowrap">
|
||||
<div className="absolute start-0 top-0 w-full h-full flex flex-col whitespace-nowrap">
|
||||
<div>{showFrom?.name || 'Noname'}</div>
|
||||
<div className="text-[12px] w-full overflow-ellipsis overflow-hidden">
|
||||
{message.messages[0]?.content}
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ export const Messages = () => {
|
|||
</div>
|
||||
<div className="flex-1 min-h-[658px] max-h-[658px] relative">
|
||||
<div
|
||||
className="pt-[18px] pb-[18px] absolute top-0 left-0 w-full h-full px-[24px] flex flex-col gap-[24px] overflow-x-hidden overflow-y-auto"
|
||||
className="pt-[18px] pb-[18px] absolute top-0 start-0 w-full h-full px-[24px] flex flex-col gap-[24px] overflow-x-hidden overflow-y-auto"
|
||||
onScroll={changeScroll}
|
||||
ref={ref}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ export const NotificationOpenComponent = () => {
|
|||
return (
|
||||
<div
|
||||
id="notification-popup"
|
||||
className="opacity-0 animate-normalFadeDown mt-[10px] absolute w-[420px] min-h-[200px] top-[100%] right-0 bg-third text-textColor rounded-[16px] flex flex-col border border-tableBorder z-[20]"
|
||||
className="opacity-0 animate-normalFadeDown mt-[10px] absolute w-[420px] min-h-[200px] top-[100%] end-0 bg-third text-textColor rounded-[16px] flex flex-col border border-tableBorder z-[20]"
|
||||
>
|
||||
<div
|
||||
className={`p-[16px] border-b border-tableBorder ${interClass} font-bold`}
|
||||
|
|
@ -113,7 +113,7 @@ const NotificationComponent = () => {
|
|||
<div className="relative cursor-pointer select-none" ref={ref}>
|
||||
<div onClick={changeShow}>
|
||||
{data && data.total > 0 && (
|
||||
<div className="w-[13px] h-[13px] bg-red-500 rounded-full absolute -left-[2px] -top-[2px] text-[10px] text-center flex justify-center items-center">
|
||||
<div className="w-[13px] h-[13px] bg-red-500 rounded-full absolute -start-[2px] -top-[2px] text-[10px] text-center flex justify-center items-center">
|
||||
{data.total}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -242,14 +242,14 @@ export const ConnectChannels: FC = () => {
|
|||
return (
|
||||
<>
|
||||
{!!showCustom && (
|
||||
<div className="absolute w-full h-full top-0 left-0 bg-black/40 z-[400]">
|
||||
<div className="absolute w-full h-full bg-primary/80 left-0 top-0 z-[200] p-[50px] flex justify-center">
|
||||
<div className="absolute w-full h-full top-0 start-0 bg-black/40 z-[400]">
|
||||
<div className="absolute w-full h-full bg-primary/80 start-0 top-0 z-[200] p-[50px] flex justify-center">
|
||||
<div className="w-[400px]">{showCustom}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!!identifier && (
|
||||
<div className="absolute w-full h-full bg-primary/80 left-0 top-0 z-[200] p-[30px] flex items-center justify-center">
|
||||
<div className="absolute w-full h-full bg-primary/80 start-0 top-0 z-[200] p-[30px] flex items-center justify-center">
|
||||
<div className="w-[400px]">
|
||||
<ApiModal
|
||||
close={() => setIdentifier(undefined)}
|
||||
|
|
@ -347,13 +347,13 @@ export const ConnectChannels: FC = () => {
|
|||
>
|
||||
{integration.inBetweenSteps && (
|
||||
<div
|
||||
className="absolute left-0 top-0 w-[39px] h-[46px] cursor-pointer"
|
||||
className="absolute start-0 top-0 w-[39px] h-[46px] cursor-pointer"
|
||||
onClick={continueIntegration(integration)}
|
||||
>
|
||||
<div className="bg-red-500 w-[15px] h-[15px] rounded-full -left-[5px] -top-[5px] absolute z-[200] text-[10px] flex justify-center items-center">
|
||||
<div className="bg-red-500 w-[15px] h-[15px] rounded-full -start-[5px] -top-[5px] absolute z-[200] text-[10px] flex justify-center items-center">
|
||||
!
|
||||
</div>
|
||||
<div className="bg-primary/60 w-[39px] h-[46px] left-0 top-0 absolute rounded-full z-[199]" />
|
||||
<div className="bg-primary/60 w-[39px] h-[46px] start-0 top-0 absolute rounded-full z-[199]" />
|
||||
</div>
|
||||
)}
|
||||
<Image
|
||||
|
|
@ -365,7 +365,7 @@ export const ConnectChannels: FC = () => {
|
|||
/>
|
||||
<Image
|
||||
src={`/icons/platforms/${integration.identifier}.png`}
|
||||
className="rounded-full absolute z-10 -bottom-[5px] -right-[5px] border border-fifth"
|
||||
className="rounded-full absolute z-10 -bottom-[5px] -end-[5px] border border-fifth"
|
||||
alt={integration.identifier}
|
||||
width={20}
|
||||
height={20}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ export const PlatformAnalytics = () => {
|
|||
) {
|
||||
arr.push({
|
||||
key: 7,
|
||||
value: '7 Days',
|
||||
value: t('7_days', '7 Days'),
|
||||
});
|
||||
}
|
||||
if (
|
||||
|
|
@ -85,7 +85,7 @@ export const PlatformAnalytics = () => {
|
|||
) {
|
||||
arr.push({
|
||||
key: 30,
|
||||
value: '30 Days',
|
||||
value: t('30_days', '30 Days'),
|
||||
});
|
||||
}
|
||||
if (
|
||||
|
|
@ -95,7 +95,7 @@ export const PlatformAnalytics = () => {
|
|||
) {
|
||||
arr.push({
|
||||
key: 90,
|
||||
value: '90 Days',
|
||||
value: t('90_days', '90 Days'),
|
||||
});
|
||||
}
|
||||
return arr;
|
||||
|
|
@ -176,11 +176,11 @@ export const PlatformAnalytics = () => {
|
|||
)}
|
||||
>
|
||||
{(integration.inBetweenSteps || integration.refreshNeeded) && (
|
||||
<div className="absolute left-0 top-0 w-[39px] h-[46px] cursor-pointer">
|
||||
<div className="bg-red-500 w-[15px] h-[15px] rounded-full left-0 -top-[5px] absolute z-[200] text-[10px] flex justify-center items-center">
|
||||
<div className="absolute start-0 top-0 w-[39px] h-[46px] cursor-pointer">
|
||||
<div className="bg-red-500 w-[15px] h-[15px] rounded-full start-0 -top-[5px] absolute z-[200] text-[10px] flex justify-center items-center">
|
||||
!
|
||||
</div>
|
||||
<div className="bg-primary/60 w-[39px] h-[46px] left-0 top-0 absolute rounded-full z-[199]" />
|
||||
<div className="bg-primary/60 w-[39px] h-[46px] start-0 top-0 absolute rounded-full z-[199]" />
|
||||
</div>
|
||||
)}
|
||||
<ImageWithFallback
|
||||
|
|
@ -193,7 +193,7 @@ export const PlatformAnalytics = () => {
|
|||
/>
|
||||
<Image
|
||||
src={`/icons/platforms/${integration.identifier}.png`}
|
||||
className="rounded-full absolute z-10 -bottom-[5px] -right-[5px] border border-fifth"
|
||||
className="rounded-full absolute z-10 -bottom-[5px] -end-[5px] border border-fifth"
|
||||
alt={integration.identifier}
|
||||
width={20}
|
||||
height={20}
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ export const PlugPop: FC<{
|
|||
return (
|
||||
<FormProvider {...form}>
|
||||
<form onSubmit={form.handleSubmit(submit)}>
|
||||
<div className="fixed left-0 top-0 bg-primary/80 z-[300] w-full min-h-full p-4 md:p-[60px] animate-fade">
|
||||
<div className="fixed start-0 top-0 bg-primary/80 z-[300] w-full min-h-full p-4 md:p-[60px] animate-fade">
|
||||
<div className="max-w-[1000px] w-full h-full bg-sixth border-tableBorder border-2 rounded-xl pb-[20px] px-[20px] relative mx-auto">
|
||||
<div className="flex flex-col">
|
||||
<div className="flex-1">
|
||||
|
|
@ -141,7 +141,7 @@ export const PlugPop: FC<{
|
|||
</div>
|
||||
<button
|
||||
onClick={closeAll}
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root bg-primary hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
|
|||
|
|
@ -132,11 +132,11 @@ export const Plugs = () => {
|
|||
)}
|
||||
>
|
||||
{(integration.inBetweenSteps || integration.refreshNeeded) && (
|
||||
<div className="absolute left-0 top-0 w-[39px] h-[46px] cursor-pointer">
|
||||
<div className="bg-red-500 w-[15px] h-[15px] rounded-full left-0 -top-[5px] absolute z-[200] text-[10px] flex justify-center items-center">
|
||||
<div className="absolute start-0 top-0 w-[39px] h-[46px] cursor-pointer">
|
||||
<div className="bg-red-500 w-[15px] h-[15px] rounded-full start-0 -top-[5px] absolute z-[200] text-[10px] flex justify-center items-center">
|
||||
!
|
||||
</div>
|
||||
<div className="bg-primary/60 w-[39px] h-[46px] left-0 top-0 absolute rounded-full z-[199]" />
|
||||
<div className="bg-primary/60 w-[39px] h-[46px] start-0 top-0 absolute rounded-full z-[199]" />
|
||||
</div>
|
||||
)}
|
||||
<ImageWithFallback
|
||||
|
|
@ -149,7 +149,7 @@ export const Plugs = () => {
|
|||
/>
|
||||
<Image
|
||||
src={`/icons/platforms/${integration.identifier}.png`}
|
||||
className="rounded-full absolute z-10 -bottom-[5px] -right-[5px] border border-fifth"
|
||||
className="rounded-full absolute z-10 -bottom-[5px] -end-[5px] border border-fifth"
|
||||
alt={integration.identifier}
|
||||
width={20}
|
||||
height={20}
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ export const PostSelector: FC<{
|
|||
<div
|
||||
className={
|
||||
!noModal
|
||||
? 'text-textColor fixed left-0 top-0 bg-primary/80 z-[300] w-full h-full p-[60px] animate-fade'
|
||||
? 'text-textColor fixed start-0 top-0 bg-primary/80 z-[300] w-full h-full p-[60px] animate-fade'
|
||||
: ''
|
||||
}
|
||||
>
|
||||
|
|
@ -146,7 +146,7 @@ export const PostSelector: FC<{
|
|||
</div>
|
||||
<button
|
||||
onClick={onCloseWithEmptyString}
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root bg-primary hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
@ -185,7 +185,7 @@ export const PostSelector: FC<{
|
|||
className="w-[32px] h-[32px] rounded-full"
|
||||
/>
|
||||
<img
|
||||
className="w-[20px] h-[20px] rounded-full absolute z-10 -bottom-[5px] -right-[5px] border border-fifth"
|
||||
className="w-[20px] h-[20px] rounded-full absolute z-10 -bottom-[5px] -end-[5px] border border-fifth"
|
||||
src={
|
||||
`/icons/platforms/` +
|
||||
p?.integration?.providerIdentifier +
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ export const RenderComponents: FC<{
|
|||
strokeWidth={2}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="lucide lucide-send mr-2 h-4 w-4"
|
||||
className="lucide lucide-send me-2 h-4 w-4"
|
||||
>
|
||||
<path d="m22 2-7 20-4-9-9-4Z" />
|
||||
<path d="M22 2 11 13" />
|
||||
|
|
|
|||
|
|
@ -9,7 +9,10 @@ export const CopyClient = () => {
|
|||
const toast = useToaster();
|
||||
const t = useT();
|
||||
const copyToClipboard = useCallback(() => {
|
||||
toast.show('Link copied to clipboard', 'success');
|
||||
toast.show(
|
||||
t('link_copied_to_clipboard', 'Link copied to clipboard'),
|
||||
'success'
|
||||
);
|
||||
copy(window.location.href.split?.('?')?.shift()!);
|
||||
}, []);
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -66,13 +66,13 @@ export const SignaturesComponent: FC<{
|
|||
<div className="text-center">{t('delete', 'Delete')}</div>
|
||||
{data?.map((p: any) => (
|
||||
<Fragment key={p.id}>
|
||||
<div className="relative flex-1 mr-[20px] overflow-x-hidden">
|
||||
<div className="absolute left-0 line-clamp-1 top-[50%] -translate-y-[50%] text-ellipsis">
|
||||
<div className="relative flex-1 me-[20px] overflow-x-hidden">
|
||||
<div className="absolute start-0 line-clamp-1 top-[50%] -translate-y-[50%] text-ellipsis">
|
||||
{p.content.slice(0, 15) + '...'}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col justify-center relative mr-[20px]">
|
||||
<div className="text-center w-full absolute left-0 line-clamp-1 top-[50%] -translate-y-[50%]">
|
||||
<div className="flex flex-col justify-center relative me-[20px]">
|
||||
<div className="text-center w-full absolute start-0 line-clamp-1 top-[50%] -translate-y-[50%]">
|
||||
{p.autoAdd ? 'Yes' : 'No'}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -161,7 +161,7 @@ const AddOrRemoveSignature: FC<{
|
|||
<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'} />
|
||||
<button
|
||||
className="outline-none absolute right-[20px] top-[15px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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)
|
||||
|
|
@ -203,6 +203,7 @@ const AddOrRemoveSignature: FC<{
|
|||
|
||||
<Select
|
||||
label="Auto add signature?"
|
||||
translationKey="label_auto_add_signature"
|
||||
{...form.register('autoAdd', {
|
||||
setValueAs: (value) => value === 'true',
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ export const AddMember = () => {
|
|||
<TopTitle title="Add Member" />
|
||||
<button
|
||||
onClick={closeModal}
|
||||
className="outline-none absolute right-[20px] top-[20px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
@ -99,7 +99,11 @@ export const AddMember = () => {
|
|||
</button>
|
||||
|
||||
{sendEmail && (
|
||||
<Input label="Email" placeholder="Enter email" name="email" />
|
||||
<Input
|
||||
label="Email"
|
||||
placeholder={t('enter_email', 'Enter email')}
|
||||
name="email"
|
||||
/>
|
||||
)}
|
||||
<Select label="Role" name="role">
|
||||
<option value="">{t('select_role', 'Select Role')}</option>
|
||||
|
|
|
|||
|
|
@ -46,11 +46,11 @@ export const SignatureModal: FC<{
|
|||
}> = (props) => {
|
||||
const { close, appendSignature } = props;
|
||||
return (
|
||||
<div className="bg-black/40 fixed left-0 top-0 w-full h-full z-[500]">
|
||||
<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 right-[20px] top-[15px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
import { ReactNode } from 'react';
|
||||
import { useT } from '@gitroom/react/translation/get.transation.service.client';
|
||||
|
||||
interface TranslatedLabelProps {
|
||||
label: string;
|
||||
translationKey?: string;
|
||||
translationParams?: Record<string, string | number>;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* TranslatedLabel is a wrapper component that translates labels in form components
|
||||
*
|
||||
* @param label - The original label text (fallback if no translation found)
|
||||
* @param translationKey - Optional custom translation key, defaults to normalized label text
|
||||
* @param translationParams - Optional parameters for translation interpolation
|
||||
* @param children - Optional children components
|
||||
*/
|
||||
export function TranslatedLabel({
|
||||
label,
|
||||
translationKey,
|
||||
translationParams = {},
|
||||
children,
|
||||
}: TranslatedLabelProps) {
|
||||
const t = useT();
|
||||
|
||||
// If no explicit key is provided, create one from the label
|
||||
const key =
|
||||
translationKey ||
|
||||
`label_${label.toLowerCase().replace(/\s+/g, '_').replace(/[^\w]/g, '')}`;
|
||||
|
||||
const translatedLabel = t(key, label, translationParams);
|
||||
|
||||
return (
|
||||
<>
|
||||
{translatedLabel}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -39,7 +39,15 @@ export const Webhooks: FC = () => {
|
|||
);
|
||||
const deleteHook = useCallback(
|
||||
(data: any) => async () => {
|
||||
if (await deleteDialog(`Are you sure you want to delete ${data.name}?`)) {
|
||||
if (
|
||||
await deleteDialog(
|
||||
t(
|
||||
'are_you_sure_you_want_to_delete',
|
||||
`Are you sure you want to delete ${data.name}?`,
|
||||
{ name: data.name }
|
||||
)
|
||||
)
|
||||
) {
|
||||
await fetch(`/webhooks/${data.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
|
|
@ -234,7 +242,7 @@ export const AddOrEditWebhook: FC<{
|
|||
<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 right-[20px] top-[15px] mantine-UnstyledButton-root mantine-ActionIcon-root hover:bg-tableBorder cursor-pointer mantine-Modal-close mantine-1dcetaa"
|
||||
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}
|
||||
>
|
||||
|
|
@ -255,12 +263,21 @@ export const AddOrEditWebhook: FC<{
|
|||
</button>
|
||||
|
||||
<div>
|
||||
<Input label="Name" {...form.register('name')} />
|
||||
<Input label="URL" {...form.register('url')} />
|
||||
<Input
|
||||
label="Name"
|
||||
translationKey="label_name"
|
||||
{...form.register('name')}
|
||||
/>
|
||||
<Input
|
||||
label="URL"
|
||||
translationKey="label_url"
|
||||
{...form.register('url')}
|
||||
/>
|
||||
<Select
|
||||
value={allIntegrations.value}
|
||||
name="integrations"
|
||||
label="Integrations"
|
||||
translationKey="label_integrations"
|
||||
disableForm={true}
|
||||
onChange={changeIntegration}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -205,6 +205,7 @@ module.exports = {
|
|||
},
|
||||
plugins: [
|
||||
require('tailwind-scrollbar'),
|
||||
require('tailwindcss-rtl'),
|
||||
function ({ addVariant }) {
|
||||
addVariant('child', '& > *');
|
||||
addVariant('child-hover', '& > *:hover');
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import { useFormContext } from 'react-hook-form';
|
|||
import dayjs from 'dayjs';
|
||||
import { useShowPostSelector } from '../../../../apps/frontend/src/components/post-url-selector/post.url.selector';
|
||||
import interClass from '../helpers/inter.font';
|
||||
import { TranslatedLabel } from '../translation/translated-label';
|
||||
|
||||
export const Canonical: FC<
|
||||
DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> & {
|
||||
error?: any;
|
||||
|
|
@ -19,9 +21,20 @@ export const Canonical: FC<
|
|||
disableForm?: boolean;
|
||||
label: string;
|
||||
name: string;
|
||||
translationKey?: string;
|
||||
translationParams?: Record<string, string | number>;
|
||||
}
|
||||
> = (props) => {
|
||||
const { label, date, className, disableForm, error, ...rest } = props;
|
||||
const {
|
||||
label,
|
||||
date,
|
||||
className,
|
||||
disableForm,
|
||||
error,
|
||||
translationKey,
|
||||
translationParams,
|
||||
...rest
|
||||
} = props;
|
||||
const form = useFormContext();
|
||||
const err = useMemo(() => {
|
||||
if (error) return error;
|
||||
|
|
@ -46,7 +59,13 @@ export const Canonical: FC<
|
|||
return (
|
||||
<div className="flex flex-col gap-[6px]">
|
||||
<div className="flex items-center gap-[3px]">
|
||||
<div className={`${interClass} text-[14px]`}>{label}</div>
|
||||
<div className={`${interClass} text-[14px]`}>
|
||||
<TranslatedLabel
|
||||
label={label}
|
||||
translationKey={translationKey}
|
||||
translationParams={translationParams}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<svg
|
||||
onClick={onPostSelector}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import { useFormContext } from 'react-hook-form';
|
|||
import interClass from '../helpers/inter.font';
|
||||
import { Button } from './button';
|
||||
import { useT } from '@gitroom/react/translation/get.transation.service.client';
|
||||
import { TranslatedLabel } from '../translation/translated-label';
|
||||
|
||||
export const ColorPicker: FC<{
|
||||
name: string;
|
||||
label: string;
|
||||
|
|
@ -16,8 +18,19 @@ export const ColorPicker: FC<{
|
|||
}) => void;
|
||||
value?: string;
|
||||
canBeCancelled: boolean;
|
||||
translationKey?: string;
|
||||
translationParams?: Record<string, string | number>;
|
||||
}> = (props) => {
|
||||
const { name, label, enabled, value, canBeCancelled, onChange } = props;
|
||||
const {
|
||||
name,
|
||||
label,
|
||||
enabled,
|
||||
value,
|
||||
canBeCancelled,
|
||||
onChange,
|
||||
translationKey,
|
||||
translationParams,
|
||||
} = props;
|
||||
const form = useFormContext();
|
||||
const color = onChange
|
||||
? {
|
||||
|
|
@ -59,7 +72,15 @@ export const ColorPicker: FC<{
|
|||
return (
|
||||
<div className="flex flex-col gap-[6px]">
|
||||
<div>
|
||||
{!!label && <div className={`${interClass} text-[14px]`}>{label}</div>}
|
||||
{!!label && (
|
||||
<div className={`${interClass} text-[14px]`}>
|
||||
<TranslatedLabel
|
||||
label={label}
|
||||
translationKey={translationKey}
|
||||
translationParams={translationParams}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{canBeCancelled && (
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import {
|
|||
import interClass from '../helpers/inter.font';
|
||||
import { clsx } from 'clsx';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { TranslatedLabel } from '../translation/translated-label';
|
||||
|
||||
export const CustomSelect: FC<{
|
||||
error?: any;
|
||||
disableForm?: boolean;
|
||||
|
|
@ -18,6 +20,8 @@ export const CustomSelect: FC<{
|
|||
removeError?: boolean;
|
||||
onChange?: () => void;
|
||||
className?: string;
|
||||
translationKey?: string;
|
||||
translationParams?: Record<string, string | number>;
|
||||
options: Array<{
|
||||
value: string;
|
||||
label: string;
|
||||
|
|
@ -31,6 +35,8 @@ export const CustomSelect: FC<{
|
|||
className,
|
||||
removeError,
|
||||
label,
|
||||
translationKey,
|
||||
translationParams,
|
||||
...rest
|
||||
} = props;
|
||||
const form = useFormContext();
|
||||
|
|
@ -76,14 +82,22 @@ export const CustomSelect: FC<{
|
|||
}, [value]);
|
||||
return (
|
||||
<div className={clsx('flex flex-col gap-[6px] relative', className)}>
|
||||
{!!label && <div className={`${interClass} text-[14px]`}>{label}</div>}
|
||||
{!!label && (
|
||||
<div className={`${interClass} text-[14px]`}>
|
||||
<TranslatedLabel
|
||||
label={label}
|
||||
translationKey={translationKey}
|
||||
translationParams={translationParams}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={clsx(
|
||||
'bg-input h-[44px] border-fifth border rounded-[4px] text-inputText placeholder-inputText items-center justify-center flex'
|
||||
)}
|
||||
onClick={changeOpen}
|
||||
>
|
||||
<div className="flex-1 pl-[16px] text-[14px] select-none flex gap-[8px]">
|
||||
<div className="flex-1 ps-[16px] text-[14px] select-none flex gap-[8px]">
|
||||
{!!option.icon && (
|
||||
<div className="flex justify-center items-center">
|
||||
{option.icon}
|
||||
|
|
@ -92,7 +106,7 @@ export const CustomSelect: FC<{
|
|||
|
||||
{option.label}
|
||||
</div>
|
||||
<div className="pr-[16px] flex gap-[8px]">
|
||||
<div className="pe-[16px] flex gap-[8px]">
|
||||
<div>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
|
@ -129,11 +143,12 @@ export const CustomSelect: FC<{
|
|||
<div
|
||||
className={clsx(
|
||||
label && !removeError && '-mt-[23px]',
|
||||
'z-[100] absolute w-full top-[100%] left-0 flex items-center rounded-bl-[4px] rounded-br-[4px] flex-col bg-fifth gap-[1px] border-l border-r border-b border-fifth overflow-hidden'
|
||||
'z-[100] absolute w-full top-[100%] start-0 flex items-center rounded-bl-[4px] rounded-br-[4px] flex-col bg-fifth gap-[1px] border-l border-r border-b border-fifth overflow-hidden'
|
||||
)}
|
||||
>
|
||||
{options.map((option) => (
|
||||
<div
|
||||
key={option.value}
|
||||
onClick={setOption(option)}
|
||||
className="px-[16px] py-[8px] bg-input w-full flex gap-[8px] hover:bg-customColor3 select-none cursor-pointer"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import {
|
|||
import { clsx } from 'clsx';
|
||||
import { useFormContext, useWatch } from 'react-hook-form';
|
||||
import interClass from '../helpers/inter.font';
|
||||
import { TranslatedLabel } from '../translation/translated-label';
|
||||
|
||||
export const Input: FC<
|
||||
DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> & {
|
||||
removeError?: boolean;
|
||||
|
|
@ -20,6 +22,8 @@ export const Input: FC<
|
|||
label: string;
|
||||
name: string;
|
||||
icon?: ReactNode;
|
||||
translationKey?: string;
|
||||
translationParams?: Record<string, string | number>;
|
||||
}
|
||||
> = (props) => {
|
||||
const {
|
||||
|
|
@ -30,6 +34,8 @@ export const Input: FC<
|
|||
className,
|
||||
disableForm,
|
||||
error,
|
||||
translationKey,
|
||||
translationParams,
|
||||
...rest
|
||||
} = props;
|
||||
const form = useFormContext();
|
||||
|
|
@ -46,18 +52,26 @@ export const Input: FC<
|
|||
}, [watch]);
|
||||
return (
|
||||
<div className="flex flex-col gap-[6px]">
|
||||
{!!label && <div className={`${interClass} text-[14px]`}>{label}</div>}
|
||||
{!!label && (
|
||||
<div className={`${interClass} text-[14px]`}>
|
||||
<TranslatedLabel
|
||||
label={label}
|
||||
translationKey={translationKey}
|
||||
translationParams={translationParams}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={clsx(
|
||||
'bg-input h-[44px] border-fifth border rounded-[4px] text-inputText placeholder-inputText flex items-center justify-center',
|
||||
className
|
||||
)}
|
||||
>
|
||||
{icon && <div className="pl-[16px]">{icon}</div>}
|
||||
{icon && <div className="ps-[16px]">{icon}</div>}
|
||||
<input
|
||||
className={clsx(
|
||||
'h-full bg-transparent outline-none flex-1',
|
||||
icon ? 'pl-[8px] pr-[16px]' : 'px-[16px]'
|
||||
icon ? 'pl-[8px] pe-[16px]' : 'px-[16px]'
|
||||
)}
|
||||
{...(disableForm ? {} : form.register(props.name))}
|
||||
{...rest}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import { clsx } from 'clsx';
|
|||
import { useFormContext } from 'react-hook-form';
|
||||
import interClass from '../helpers/inter.font';
|
||||
import { RegisterOptions } from 'react-hook-form/dist/types/validator';
|
||||
import { TranslatedLabel } from '../translation/translated-label';
|
||||
|
||||
export const Select: FC<
|
||||
DetailedHTMLProps<
|
||||
SelectHTMLAttributes<HTMLSelectElement>,
|
||||
|
|
@ -22,6 +24,8 @@ export const Select: FC<
|
|||
label: string;
|
||||
name: string;
|
||||
hideErrors?: boolean;
|
||||
translationKey?: string;
|
||||
translationParams?: Record<string, string | number>;
|
||||
}
|
||||
> = forwardRef((props, ref) => {
|
||||
const {
|
||||
|
|
@ -31,6 +35,8 @@ export const Select: FC<
|
|||
disableForm,
|
||||
error,
|
||||
extraForm,
|
||||
translationKey,
|
||||
translationParams,
|
||||
...rest
|
||||
} = props;
|
||||
const form = useFormContext();
|
||||
|
|
@ -41,7 +47,13 @@ export const Select: FC<
|
|||
}, [form?.formState?.errors?.[props?.name!]?.message, error]);
|
||||
return (
|
||||
<div className={clsx('flex flex-col', label ? 'gap-[6px]' : '')}>
|
||||
<div className={`${interClass} text-[14px]`}>{label}</div>
|
||||
<div className={`${interClass} text-[14px]`}>
|
||||
<TranslatedLabel
|
||||
label={label}
|
||||
translationKey={translationKey}
|
||||
translationParams={translationParams}
|
||||
/>
|
||||
</div>
|
||||
<select
|
||||
ref={ref}
|
||||
{...(disableForm ? {} : form.register(props.name, extraForm))}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export const Slider: FC<{
|
|||
<div className="w-full h-full relative rounded-[100px]">
|
||||
<div
|
||||
className={clsx(
|
||||
'absolute left-0 top-0 w-[24px] h-[24px] bg-customColor5 rounded-full transition-all cursor-pointer',
|
||||
'absolute start-0 top-0 w-[24px] h-[24px] bg-customColor5 rounded-full transition-all cursor-pointer',
|
||||
value === 'on' ? 'left-[100%] -translate-x-[100%]' : 'left-0'
|
||||
)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import { DetailedHTMLProps, FC, InputHTMLAttributes, useMemo } from 'react';
|
|||
import clsx from 'clsx';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import interClass from '../helpers/inter.font';
|
||||
import { TranslatedLabel } from '../translation/translated-label';
|
||||
|
||||
export const Textarea: FC<
|
||||
DetailedHTMLProps<
|
||||
InputHTMLAttributes<HTMLTextAreaElement>,
|
||||
|
|
@ -14,9 +16,19 @@ export const Textarea: FC<
|
|||
disableForm?: boolean;
|
||||
label: string;
|
||||
name: string;
|
||||
translationKey?: string;
|
||||
translationParams?: Record<string, string | number>;
|
||||
}
|
||||
> = (props) => {
|
||||
const { label, className, disableForm, error, ...rest } = props;
|
||||
const {
|
||||
label,
|
||||
className,
|
||||
disableForm,
|
||||
error,
|
||||
translationKey,
|
||||
translationParams,
|
||||
...rest
|
||||
} = props;
|
||||
const form = useFormContext();
|
||||
const err = useMemo(() => {
|
||||
if (error) return error;
|
||||
|
|
@ -30,7 +42,13 @@ export const Textarea: FC<
|
|||
props.disabled && 'opacity-50'
|
||||
)}
|
||||
>
|
||||
<div className={`${interClass} text-[14px]`}>{label}</div>
|
||||
<div className={`${interClass} text-[14px]`}>
|
||||
<TranslatedLabel
|
||||
label={label}
|
||||
translationKey={translationKey}
|
||||
translationParams={translationParams}
|
||||
/>
|
||||
</div>
|
||||
<textarea
|
||||
{...(disableForm ? {} : form.register(props.name))}
|
||||
className={clsx(
|
||||
|
|
|
|||
|
|
@ -1,16 +1,19 @@
|
|||
import Swal from 'sweetalert2';
|
||||
import i18next from '@gitroom/react/translation/i18next';
|
||||
|
||||
export const deleteDialog = async (
|
||||
message: string,
|
||||
confirmButton?: string,
|
||||
title?: string
|
||||
) => {
|
||||
const fire = await Swal.fire({
|
||||
title: title || 'Are you sure?',
|
||||
title: title || i18next.t('are_you_sure', 'Are you sure?'),
|
||||
text: message,
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: confirmButton || 'Yes, delete it!',
|
||||
cancelButtonText: 'No, cancel!',
|
||||
confirmButtonText:
|
||||
confirmButton || i18next.t('yes_delete_it', 'Yes, delete it!'),
|
||||
cancelButtonText: i18next.t('no_cancel', 'No, cancel!'),
|
||||
});
|
||||
return fire.isConfirmed;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,11 +3,16 @@
|
|||
import { ReactNode } from 'react';
|
||||
import { MantineProvider } from '@mantine/core';
|
||||
import { ModalsProvider } from '@mantine/modals';
|
||||
import i18next from '@gitroom/react/translation/i18next';
|
||||
export const MantineWrapper = (props: { children: ReactNode }) => {
|
||||
const dir = i18next.dir();
|
||||
|
||||
return (
|
||||
// @ts-ignore
|
||||
<MantineProvider>
|
||||
<ModalsProvider
|
||||
modalProps={{
|
||||
dir,
|
||||
classNames: {
|
||||
modal: 'bg-primary text-white border-fifth border',
|
||||
close: 'bg-black hover:bg-black cursor-pointer',
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export const Toaster = () => {
|
|||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
'animate-fadeDown rounded-[8px] gap-[18px] flex items-center overflow-hidden bg-customColor8 p-[16px] min-w-[319px] fixed left-[50%] text-white z-[300] top-[32px] -translate-x-[50%] h-[56px]',
|
||||
'animate-fadeDown rounded-[8px] gap-[18px] flex items-center overflow-hidden bg-customColor8 p-[16px] min-w-[319px] fixed start-[50%] text-white z-[300] top-[32px] -translate-x-[50%] h-[56px]',
|
||||
toasterType === 'success' ? 'shadow-greenToast' : 'shadow-yellowToast'
|
||||
)}
|
||||
>
|
||||
|
|
@ -73,7 +73,7 @@ export const Toaster = () => {
|
|||
height="56"
|
||||
viewBox="0 0 60 56"
|
||||
fill="none"
|
||||
className="absolute top-0 left-0"
|
||||
className="absolute top-0 start-0"
|
||||
>
|
||||
<g filter="url(#filter0_f_376_2968)">
|
||||
<ellipse
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import resourcesToBackend from 'i18next-resources-to-backend';
|
|||
import { initReactI18next } from 'react-i18next/initReactI18next';
|
||||
import { fallbackLng, languages, defaultNS } from './i18n.config';
|
||||
const runsOnServerSide = typeof window === 'undefined';
|
||||
|
||||
i18next
|
||||
.use(initReactI18next)
|
||||
.use(LanguageDetector)
|
||||
|
|
|
|||
|
|
@ -191,16 +191,16 @@
|
|||
"tag_a_company": "Tag a company",
|
||||
"video_length_is_invalid_must_be_up_to": "Video length is invalid, must be up to",
|
||||
"seconds": "seconds",
|
||||
"this_feature_available_only_for_photos_it_will_add_a_default_music_that_you_can_change_later": "This feature available only for photos, it will add a default music that\n you can change later.",
|
||||
"this_feature_available_only_for_photos": "This feature available only for photos, it will add a default music that you can change later.",
|
||||
"allow_user_to": "Allow User To:",
|
||||
"your_video_will_be_labeled_promotional_content": "Your video will be labeled \"Promotional Content\".",
|
||||
"this_cannot_be_changed_once_your_video_is_posted": "This cannot be changed once your video is posted.",
|
||||
"turn_on_to_disclose_that_this_video_promotes_goods_or_services": "Turn on to disclose that this video promotes goods or services in exchange for something of value. You video could promote yourself, a third party, or both.",
|
||||
"you_are_promoting_yourself_or_your_own_brand": "You are promoting yourself or your own brand.",
|
||||
"this_video_will_be_classified_as_brand_organic": "This video will be classified as Brand Organic.",
|
||||
"you_are_promoting_another_brand_or_a_third_party": "You are promoting another brand or a third party.",
|
||||
"this_video_will_be_classified_as_branded_content": "This video will be classified as Branded Content.",
|
||||
"by_posting_you_agree_to_tiktok_s": "By posting, you agree to TikTok's",
|
||||
"your_video_will_be_labeled_promotional": "Your video will be labeled \"Promotional Content\".",
|
||||
"this_cannot_be_changed_once_posted": "This cannot be changed once your video is posted.",
|
||||
"turn_on_to_disclose_video_promotes": "Turn on to disclose that this video promotes goods or services in exchange for something of value. You video could promote yourself, a third party, or both.",
|
||||
"you_are_promoting_yourself": "You are promoting yourself or your own brand.",
|
||||
"this_video_will_be_classified_brand_organic": "This video will be classified as Brand Organic.",
|
||||
"you_are_promoting_another_brand": "You are promoting another brand or a third party.",
|
||||
"this_video_will_be_classified_branded_content": "This video will be classified as Branded Content.",
|
||||
"by_posting_you_agree_to_tiktoks": "By posting, you agree to TikTok's",
|
||||
"music_usage_confirmation": "Music Usage Confirmation",
|
||||
"branded_content_policy": "Branded Content Policy",
|
||||
"select_1": "--Select--",
|
||||
|
|
@ -320,5 +320,166 @@
|
|||
"duplicate_post": "Duplicate Post",
|
||||
"preview_post": "Preview Post",
|
||||
"post_statistics": "Post Statistics",
|
||||
"draft": "Draft"
|
||||
"draft": "Draft",
|
||||
"week_number": "Week {{number}}",
|
||||
"top_title_edit_webhook": "Edit webhook",
|
||||
"top_title_add_webhook": "Add webhook",
|
||||
"top_title_oh_no": "Oh no",
|
||||
"top_title_auto_plug": "Auto Plug: {{title}}",
|
||||
"top_title_edit_autopost": "Edit autopost",
|
||||
"top_title_add_autopost": "Add autopost",
|
||||
"top_title_send_a_new_offer": "Send a new offer",
|
||||
"top_title_media_library": "Media Library",
|
||||
"top_title_add_signature": "Add signature",
|
||||
"top_title_send_a_message_to": "Send a message to {{name}}",
|
||||
"top_title_configure_provider": "Configure Provider",
|
||||
"top_title_add_member": "Add Member",
|
||||
"top_title_change_bot_picture": "Change Bot Picture",
|
||||
"top_title_create_a_new_tag": "Create a new tag",
|
||||
"top_title_select_company": "Select Company",
|
||||
"top_title_additional_settings": "Additional Settings",
|
||||
"top_title_time_table_slots": "Time Table Slots",
|
||||
"top_title_design_media": "Design Media",
|
||||
"top_title_edit_post": "Edit Post",
|
||||
"top_title_create_post": "Create Post",
|
||||
"top_title_move__add_to_customer": "Move / Add to customer",
|
||||
"top_title_add_api_key_for": "Add API key for {{name}}",
|
||||
"top_title_instance_url": "Instance URL",
|
||||
"top_title_custom_url": "Custom URL",
|
||||
"top_title_add_channel": "Add Channel",
|
||||
"top_title_add_telegram": "Add Telegram",
|
||||
"top_title_add_wrapcast": "Add Wrapcast",
|
||||
"top_title_comments_for": "Comments for {{date}}",
|
||||
"top_title_edit_signature": "Edit Signature",
|
||||
"label_name": "Name",
|
||||
"label_url": "URL",
|
||||
"label_title": "Title",
|
||||
"label_subtitle": "Subtitle",
|
||||
"label_email": "Email",
|
||||
"label_full_name": "Full Name",
|
||||
"label_password": "Password",
|
||||
"label_confirm_password": "Confirm Password",
|
||||
"label_api_key": "API Key",
|
||||
"label_instance_url": "Instance URL",
|
||||
"label_custom_url": "Custom URL",
|
||||
"label_feedback": "Feedback",
|
||||
"label_bio": "Bio",
|
||||
"label_role": "Role",
|
||||
"label_country": "Country",
|
||||
"label_audience_size": "Audience size on all platforms",
|
||||
"label_pick_time": "Pick time",
|
||||
"label_nickname": "Nickname",
|
||||
"label_write_anything": "Write anything",
|
||||
"label_output_format": "Output format",
|
||||
"label_add_pictures": "Add pictures?",
|
||||
"label_hour": "Hour",
|
||||
"label_minutes": "Minutes",
|
||||
"label_select_publication": "Select publication",
|
||||
"label_canonical_link": "Canonical Link",
|
||||
"label_cover_picture": "Cover picture",
|
||||
"label_tags": "Tags",
|
||||
"label_topics": "Topics",
|
||||
"label_tags_maximum_4": "Tags (Maximum 4)",
|
||||
"label_attachments": "Attachments",
|
||||
"label_type": "Type",
|
||||
"label_thumbnail": "Thumbnail",
|
||||
"label_who_can_see_this_video": "Who can see this video?",
|
||||
"label_content_posting_method": "Content posting method",
|
||||
"label_auto_add_music": "Auto add music",
|
||||
"label_duet": "Duet",
|
||||
"label_stitch": "Stitch",
|
||||
"label_comments": "Comments",
|
||||
"label_disclose_video_content": "Disclose Video Content",
|
||||
"label_your_brand": "Your brand",
|
||||
"label_branded_content": "Branded content",
|
||||
"label_subreddit": "Subreddit",
|
||||
"label_flair": "Flair",
|
||||
"label_media": "Media",
|
||||
"label_search_subreddit": "Search Subreddit",
|
||||
"label_delay": "Delay",
|
||||
"label_post_type": "Post Type",
|
||||
"label_collaborators": "Collaborators (max 3) - accounts can't be private",
|
||||
"label_community": "Community",
|
||||
"label_search_community": "Search Community",
|
||||
"label_channel": "Channel",
|
||||
"label_search_channel": "Search Channel",
|
||||
"label_select_channel": "Select Channel",
|
||||
"label_new_password": "New Password",
|
||||
"label_repeat_password": "Repeat Password",
|
||||
"label_platform": "Platform",
|
||||
"label_price_per_post": "Price per post",
|
||||
"label_integrations": "Integrations",
|
||||
"label_code": "Code",
|
||||
"label_should_sync_last_post": "Should we sync the current last post?",
|
||||
"label_when_post": "When should we post it?",
|
||||
"label_autogenerate_content": "Autogenerate content",
|
||||
"label_generate_picture": "Generate Picture?",
|
||||
"label_company": "Company",
|
||||
"label_tag_color": "Tag Color",
|
||||
"label_select_board": "Select board",
|
||||
"label_select_organization": "Select organization",
|
||||
"label_auto_add_signature": "Auto add signature?",
|
||||
"enable_color_picker": "Enable color picker",
|
||||
"cancel_the_color_picker": "Cancel the color picker",
|
||||
"no_content_yet": "No Content Yet",
|
||||
"write_your_reply": "Write your reply...",
|
||||
"add_a_tag": "Add a tag",
|
||||
"add_to_calendar": "Add to Calendar",
|
||||
"select_channels_from_circles": "Select channels from the circles above",
|
||||
"not_matching_order": "Not matching order",
|
||||
"submit_for_order": "Submit for order",
|
||||
"schedule": "Schedule",
|
||||
"update": "Update",
|
||||
"attachments": "Attachments",
|
||||
"tags": "Tags",
|
||||
"public_to_everyone": "Public to everyone",
|
||||
"mutual_follow_friends": "Mutual follow friends",
|
||||
"follower_of_creator": "Follower of creator",
|
||||
"self_only": "Self only",
|
||||
"post_content_directly_to_tiktok": "Post content directly to TikTok",
|
||||
"upload_content_to_tiktok_without_posting": "Upload content to TikTok without posting it",
|
||||
"choose_upload_without_posting_description": "Choose upload without posting if you want to review and edit your content within TikTok's app before publishing. This gives you access to TikTok's built-in editing tools and lets you make final adjustments before posting.",
|
||||
"faq_am_i_going_to_be_charged_by_postiz": "Am I going to be charged by Postiz?",
|
||||
"faq_to_confirm_credit_card_information_postiz_will_hold": "To confirm credit card information Postiz will hold $2 and release it immediately",
|
||||
"faq_can_i_trust_postiz_gitroom": "Can I trust Postiz/Gitroom?",
|
||||
"faq_postiz_gitroom_is_proudly_open_source": "Postiz/Gitroom is proudly open-source! We believe in an ethical and transparent culture, meaning that Postiz/Gitroom will live forever. You can check out the entire code or use it for personal projects. To view the open-source repository, <a href=\"https://github.com/gitroomhq/postiz-app\" target=\"_blank\" style=\"text-decoration: underline;\">click here</a>.",
|
||||
"faq_what_are_channels": "What are channels?",
|
||||
"faq_postiz_gitroom_allows_you_to_schedule_posts": "Postiz/Gitroom allows you to schedule your posts between different channels.\nA channel is a publishing platform where you can schedule your posts.\nFor example, you can schedule your posts on X, Facebook, Instagram, TikTok, YouTube, Reddit, Linkedin, Dribbble, Threads and Pinterest.",
|
||||
"faq_what_are_team_members": "What are team members?",
|
||||
"faq_if_you_have_a_team_with_multiple_members": "If you have a team with multiple members, you can invite them to your workspace to collaborate on your posts and add their personal channels",
|
||||
"faq_what_is_ai_auto_complete": "What is AI auto-complete?",
|
||||
"faq_we_automate_chatgpt_to_help_you_write": "We automate ChatGPT to help you write social posts and articles.",
|
||||
"enter_email": "Enter email",
|
||||
"are_you_sure": "Are you sure?",
|
||||
"yes_delete_it": "Yes, delete it!",
|
||||
"no_cancel": "No, cancel!",
|
||||
"are_you_sure_you_want_to_delete": "Are you sure you want to delete {{name}}?",
|
||||
"are_you_sure_you_want_to_delete_the_image": "Are you sure you want to delete the image?",
|
||||
"are_you_sure_you_want_to_logout": "Are you sure you want to logout?",
|
||||
"yes_logout": "Yes logout",
|
||||
"are_you_sure_you_want_to_delete_this_slot": "Are you sure you want to delete this slot?",
|
||||
"are_you_sure_you_want_to_delete_this_subreddit": "Are you sure you want to delete this Subreddit?",
|
||||
"are_you_sure_you_want_to_close_the_window": "Are you sure you want to close the window?",
|
||||
"yes_close": "Yes, close",
|
||||
"link_copied_to_clipboard": "Link copied to clipboard",
|
||||
"are_you_sure_you_want_to_close_this_modal_all_data_will_be_lost": "Are you sure you want to close this modal? (all data will be lost)",
|
||||
"yes_close_it": "Yes, close it!",
|
||||
"uploading_pictures": "Uploading pictures...",
|
||||
"agent_starting": "Agent starting",
|
||||
"researching_your_content": "Researching your content...",
|
||||
"understanding_the_category": "Understanding the category...",
|
||||
"finding_the_topic": "Finding the topic...",
|
||||
"finding_popular_posts_to_match_with": "Finding popular posts to match with...",
|
||||
"generating_hook": "Generating hook...",
|
||||
"generating_content": "Generating content...",
|
||||
"generating_pictures": "Generating pictures...",
|
||||
"finding_time_to_post": "Finding time to post...",
|
||||
"write_anything": "Write anything",
|
||||
"you_can_write_anything_you_want_and_also_add_links_we_will_do_the_research_for_you": "You can write anything you want, and also add links, we will do the research for you...",
|
||||
"output_format": "Output format",
|
||||
"add_pictures": "Add pictures?",
|
||||
"7_days": "7 Days",
|
||||
"30_days": "30 Days",
|
||||
"90_days": "90 Days",
|
||||
"start_7_days_free_trial": "Start 7 days free trial"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@
|
|||
"tag_a_company": "תייג חברה",
|
||||
"video_length_is_invalid_must_be_up_to": "אורך הסרטון אינו חוקי, חייב להיות עד",
|
||||
"seconds": "שניות",
|
||||
"this_feature_available_only_for_photos_it_will_add_a_default_music_that_you_can_change_later": "תכונה זו זמינה רק עבור תמונות, היא תוסיף מוזיקת ברירת מחדל שתוכל לשנות מאוחר יותר.",
|
||||
"this_feature_available_only_for_photos_it_will_add_a_default_music_that_you_can_change_later": "תכונה זו זמינה רק לתמונות, היא תוסיף מוזיקת ברירת מחדל שתוכל לשנות מאוחר יותר.",
|
||||
"allow_user_to": "אפשר למשתמש:",
|
||||
"your_video_will_be_labeled_promotional_content": "הסרטון שלך יסומן כ\"תוכן פרסומי\".",
|
||||
"this_cannot_be_changed_once_your_video_is_posted": "לא ניתן לשנות זאת לאחר פרסום הסרטון שלך.",
|
||||
|
|
@ -320,5 +320,179 @@
|
|||
"duplicate_post": "שכפל פוסט",
|
||||
"preview_post": "הצג תצוגה מקדימה של הפוסט",
|
||||
"post_statistics": "סטטיסטיקות פוסט",
|
||||
"draft": "טיוטה"
|
||||
"draft": "טיוטה",
|
||||
"week_number": "שבוע {{number}}",
|
||||
"top_title_edit_webhook": "ערוך וובהוק",
|
||||
"top_title_add_webhook": "הוסף וובהוק",
|
||||
"top_title_oh_no": "אוי לא",
|
||||
"top_title_auto_plug": "חיבור אוטומטי: {{title}}",
|
||||
"top_title_edit_autopost": "ערוך פרסום אוטומטי",
|
||||
"top_title_add_autopost": "הוסף פרסום אוטומטי",
|
||||
"top_title_send_a_new_offer": "שלח הצעה חדשה",
|
||||
"top_title_media_library": "ספריית מדיה",
|
||||
"top_title_add_signature": "הוסף חתימה",
|
||||
"top_title_send_a_message_to": "שלח הודעה אל {{name}}",
|
||||
"top_title_configure_provider": "הגדר ספק",
|
||||
"top_title_add_member": "הוסף חבר",
|
||||
"top_title_change_bot_picture": "שנה תמונת בוט",
|
||||
"top_title_create_a_new_tag": "צור תגית חדשה",
|
||||
"top_title_select_company": "בחר חברה",
|
||||
"top_title_additional_settings": "הגדרות נוספות",
|
||||
"top_title_time_table_slots": "משבצות זמן",
|
||||
"top_title_design_media": "עיצוב מדיה",
|
||||
"top_title_edit_post": "ערוך פוסט",
|
||||
"top_title_create_post": "צור פוסט",
|
||||
"top_title_move__add_to_customer": "העבר / הוסף ללקוח",
|
||||
"top_title_add_api_key_for": "הוסף מפתח API עבור {{name}}",
|
||||
"top_title_instance_url": "כתובת מופע",
|
||||
"top_title_custom_url": "כתובת מותאמת אישית",
|
||||
"top_title_add_channel": "הוסף ערוץ",
|
||||
"top_title_add_telegram": "הוסף טלגרם",
|
||||
"top_title_add_wrapcast": "הוסף Wrapcast",
|
||||
"top_title_comments_for": "תגובות עבור {{date}}",
|
||||
"top_title_edit_signature": "ערוך חתימה",
|
||||
"label_name": "שם",
|
||||
"label_url": "כתובת URL",
|
||||
"label_title": "כותרת",
|
||||
"label_subtitle": "כותרת משנה",
|
||||
"label_email": "דוא\"ל",
|
||||
"label_full_name": "שם מלא",
|
||||
"label_password": "סיסמה",
|
||||
"label_confirm_password": "אימות סיסמה",
|
||||
"label_api_key": "מפתח API",
|
||||
"label_instance_url": "כתובת מופע",
|
||||
"label_custom_url": "כתובת מותאמת אישית",
|
||||
"label_feedback": "משוב",
|
||||
"label_bio": "ביוגרפיה",
|
||||
"label_role": "תפקיד",
|
||||
"label_country": "מדינה",
|
||||
"label_audience_size": "גודל קהל בכל הפלטפורמות",
|
||||
"label_pick_time": "בחר זמן",
|
||||
"label_nickname": "כינוי",
|
||||
"label_write_anything": "כתוב כל דבר",
|
||||
"label_output_format": "פורמט פלט",
|
||||
"label_add_pictures": "להוסיף תמונות?",
|
||||
"label_hour": "שעה",
|
||||
"label_minutes": "דקות",
|
||||
"label_select_publication": "בחר פרסום",
|
||||
"label_canonical_link": "קישור קנוני",
|
||||
"label_cover_picture": "תמונת שער",
|
||||
"label_tags": "תגיות",
|
||||
"label_topics": "נושאים",
|
||||
"label_tags_maximum_4": "תגיות (מקסימום 4)",
|
||||
"label_attachments": "קבצים מצורפים",
|
||||
"label_type": "סוג",
|
||||
"label_thumbnail": "תמונה ממוזערת",
|
||||
"label_who_can_see_this_video": "מי יכול לראות את הסרטון הזה?",
|
||||
"label_content_posting_method": "שיטת פרסום תוכן",
|
||||
"label_auto_add_music": "הוספת מוזיקה אוטומטית",
|
||||
"label_duet": "דואט",
|
||||
"label_stitch": "סטיץ'",
|
||||
"label_comments": "תגובות",
|
||||
"label_disclose_video_content": "חשיפת תוכן הסרטון",
|
||||
"label_your_brand": "המותג שלך",
|
||||
"label_branded_content": "תוכן ממותג",
|
||||
"label_subreddit": "סאברדיט",
|
||||
"label_flair": "פלייר",
|
||||
"label_media": "מדיה",
|
||||
"label_search_subreddit": "חיפוש סאברדיט",
|
||||
"label_delay": "עיכוב",
|
||||
"label_post_type": "סוג פוסט",
|
||||
"label_collaborators": "משתפי פעולה (מקסימום 3) - חשבונות לא יכולים להיות פרטיים",
|
||||
"label_community": "קהילה",
|
||||
"label_search_community": "חיפוש קהילה",
|
||||
"label_channel": "ערוץ",
|
||||
"label_search_channel": "חיפוש ערוץ",
|
||||
"label_select_channel": "בחר ערוץ",
|
||||
"label_new_password": "סיסמה חדשה",
|
||||
"label_repeat_password": "חזור על הסיסמה",
|
||||
"label_platform": "פלטפורמה",
|
||||
"label_price_per_post": "מחיר לפוסט",
|
||||
"label_integrations": "אינטגרציות",
|
||||
"label_code": "קוד",
|
||||
"label_should_sync_last_post": "האם לסנכרן את הפוסט האחרון הנוכחי?",
|
||||
"label_when_post": "מתי לפרסם את זה?",
|
||||
"label_autogenerate_content": "יצירת תוכן אוטומטית",
|
||||
"label_generate_picture": "ליצור תמונה?",
|
||||
"label_company": "חברה",
|
||||
"label_tag_color": "צבע תגית",
|
||||
"label_select_board": "בחר לוח",
|
||||
"label_select_organization": "בחר ארגון",
|
||||
"label_auto_add_signature": "הוסף חתימה אוטומטית?",
|
||||
"enable_color_picker": "הפעל בוחר צבעים",
|
||||
"cancel_the_color_picker": "בטל את בוחר הצבעים",
|
||||
"no_content_yet": "אין תוכן עדיין",
|
||||
"write_your_reply": "כתוב את תגובתך...",
|
||||
"add_a_tag": "הוסף תגית",
|
||||
"add_to_calendar": "הוסף ליומן",
|
||||
"select_channels_from_circles": "בחר ערוצים מהעיגולים למעלה",
|
||||
"not_matching_order": "לא תואם להזמנה",
|
||||
"submit_for_order": "הגש להזמנה",
|
||||
"schedule": "תזמן",
|
||||
"update": "עדכן",
|
||||
"attachments": "קבצים מצורפים",
|
||||
"tags": "תגיות",
|
||||
"public_to_everyone": "ציבורי לכולם",
|
||||
"mutual_follow_friends": "חברים עם מעקב הדדי",
|
||||
"follower_of_creator": "עוקבי היוצר",
|
||||
"self_only": "רק אני",
|
||||
"post_content_directly_to_tiktok": "פרסם תוכן ישירות לטיקטוק",
|
||||
"upload_content_to_tiktok_without_posting": "העלה תוכן לטיקטוק מבלי לפרסם",
|
||||
"choose_upload_without_posting_description": "בחר העלאה ללא פרסום אם אתה רוצה לסקור ולערוך את התוכן שלך באפליקציה של טיקטוק לפני הפרסום. זה נותן לך גישה לכלי העריכה המובנים של טיקטוק ומאפשר לך לבצע התאמות אחרונות לפני הפרסום.",
|
||||
"and": "ו",
|
||||
"this_feature_available_only_for_photos": "תכונה זו זמינה רק לתמונות, היא תוסיף מוזיקה ברירת מחדל שתוכל לשנות מאוחר יותר.",
|
||||
"allow_user_to": "אפשר למשתמש:",
|
||||
"your_video_will_be_labeled_promotional": "הסרטון שלך יסומן כ\"תוכן פרסומי\".",
|
||||
"this_cannot_be_changed_once_posted": "לא ניתן לשנות זאת לאחר פרסום הסרטון.",
|
||||
"turn_on_to_disclose_video_promotes": "הפעל כדי לחשף שהסרטון הזה מקדם מוצרים או שירותים בתמורה למשהו בעל ערך. הסרטון שלך יכול לקדם אותך, צד שלישי, או שניהם.",
|
||||
"you_are_promoting_yourself": "אתה מקדם את עצמך או את המותג שלך.",
|
||||
"this_video_will_be_classified_brand_organic": "הסרטון הזה יסווג כמותג אורגני.",
|
||||
"you_are_promoting_another_brand": "אתה מקדם מותג אחר או צד שלישי.",
|
||||
"this_video_will_be_classified_branded_content": "הסרטון הזה יסווג כתוכן ממותג.",
|
||||
"by_posting_you_agree_to_tiktoks": "על ידי פרסום, אתה מסכים ל",
|
||||
"music_usage_confirmation": "אישור שימוש במוזיקה",
|
||||
"branded_content_policy": "מדיניות תוכן ממותג",
|
||||
"faq_am_i_going_to_be_charged_by_postiz": "האם אני אחויב על ידי פוסטיז?",
|
||||
"faq_to_confirm_credit_card_information_postiz_will_hold": "כדי לאמת פרטי כרטיס אשראי, פוסטיז יחזיק 2$ וישחרר אותם מיד",
|
||||
"faq_can_i_trust_postiz_gitroom": "האם אני יכול לסמוך על פוסטיז/גיטרום?",
|
||||
"faq_postiz_gitroom_is_proudly_open_source": "פוסטיז/גיטרום הוא בגאווה קוד פתוח! אנחנו מאמינים בתרבות אתית ושקופה, כלומר פוסטיז/גיטרום יחיה לנצח. אתה יכול לבדוק את כל הקוד או להשתמש בו לפרויקטים אישיים. כדי לצפות במאגר הקוד הפתוח, <a href=\"https://github.com/gitroomhq/postiz-app\" target=\"_blank\" style=\"text-decoration: underline;\">לחץ כאן</a>.",
|
||||
"faq_what_are_channels": "מה הם ערוצים?",
|
||||
"faq_postiz_gitroom_allows_you_to_schedule_posts": "פוסטיז/גיטרום מאפשר לך לתזמן את הפוסטים שלך בין ערוצים שונים.\nערוץ הוא פלטפורמת פרסום שבה אתה יכול לתזמן את הפוסטים שלך.\nלמשל, אתה יכול לתזמן את הפוסטים שלך ב-X, פייסבוק, אינסטגרם, טיקטוק, יוטיוב, רדיט, לינקדאין, דריבל, Threads ופינטרסט.",
|
||||
"faq_what_are_team_members": "מה הם חברי צוות?",
|
||||
"faq_if_you_have_a_team_with_multiple_members": "אם יש לך צוות עם מספר חברים, אתה יכול להזמין אותם לסביבת העבודה שלך כדי לשתף פעולה בפוסטים שלך ולהוסיף את הערוצים האישיים שלהם",
|
||||
"faq_what_is_ai_auto_complete": "מה זה השלמה אוטומטית של AI?",
|
||||
"faq_we_automate_chatgpt_to_help_you_write": "אנו מפעילים את ChatGPT כדי לעזור לך לכתוב פוסטים ומאמרים ברשתות החברתיות.",
|
||||
"enter_email": "הזן אימייל",
|
||||
"are_you_sure": "האם אתה בטוח?",
|
||||
"yes_delete_it": "כן, מחק את זה!",
|
||||
"no_cancel": "לא, בטל!",
|
||||
"are_you_sure_you_want_to_delete": "האם אתה בטוח שברצונך למחוק את {{name}}?",
|
||||
"are_you_sure_you_want_to_delete_the_image": "האם אתה בטוח שברצונך למחוק את התמונה?",
|
||||
"are_you_sure_you_want_to_logout": "האם אתה בטוח שברצונך להתנתק?",
|
||||
"yes_logout": "כן התנתק",
|
||||
"are_you_sure_you_want_to_delete_this_slot": "האם אתה בטוח שברצונך למחוק את המשבצת הזו?",
|
||||
"are_you_sure_you_want_to_delete_this_subreddit": "האם אתה בטוח שברצונך למחוק את הסאברדיט הזה?",
|
||||
"are_you_sure_you_want_to_close_the_window": "האם אתה בטוח שברצונך לסגור את החלון?",
|
||||
"yes_close": "כן, סגור",
|
||||
"link_copied_to_clipboard": "הקישור הועתק ללוח",
|
||||
"are_you_sure_you_want_to_close_this_modal_all_data_will_be_lost": "האם אתה בטוח שברצונך לסגור את החלון הזה? (כל הנתונים יאבדו)",
|
||||
"yes_close_it": "כן, סגור את זה!",
|
||||
"uploading_pictures": "מעלה תמונות...",
|
||||
"agent_starting": "הסוכן מתחיל",
|
||||
"researching_your_content": "חוקר את התוכן שלך...",
|
||||
"understanding_the_category": "מבין את הקטגוריה...",
|
||||
"finding_the_topic": "מוצא את הנושא...",
|
||||
"finding_popular_posts_to_match_with": "מוצא פוסטים פופולריים להתאמה...",
|
||||
"generating_hook": "יוצר הוק...",
|
||||
"generating_content": "יוצר תוכן...",
|
||||
"generating_pictures": "יוצר תמונות...",
|
||||
"finding_time_to_post": "מוצא זמן לפרסום...",
|
||||
"write_anything": "כתוב כל דבר",
|
||||
"you_can_write_anything_you_want_and_also_add_links_we_will_do_the_research_for_you": "אתה יכול לכתוב כל דבר שאתה רוצה, וגם להוסיף קישורים, אנחנו נעשה עבורך את המחקר...",
|
||||
"output_format": "פורמט פלט",
|
||||
"add_pictures": "להוסיף תמונות?",
|
||||
"7_days": "7 ימים",
|
||||
"30_days": "30 ימים",
|
||||
"90_days": "90 ימים",
|
||||
"start_7_days_free_trial": "התחל ניסיון חינם ל-7 ימים"
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import { ReactNode } from 'react';
|
||||
import { useT } from './get.transation.service.client';
|
||||
|
||||
interface TranslatedLabelProps {
|
||||
label: string;
|
||||
translationKey?: string;
|
||||
translationParams?: Record<string, string | number>;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* TranslatedLabel is a wrapper component that translates labels in form components
|
||||
*
|
||||
* @param label - The original label text (fallback if no translation found)
|
||||
* @param translationKey - Optional custom translation key, defaults to normalized label text
|
||||
* @param translationParams - Optional parameters for translation interpolation
|
||||
* @param children - Optional children components
|
||||
*/
|
||||
export function TranslatedLabel({
|
||||
label,
|
||||
translationKey,
|
||||
translationParams = {},
|
||||
children,
|
||||
}: TranslatedLabelProps) {
|
||||
const t = useT();
|
||||
|
||||
// If no explicit key is provided, create one from the label
|
||||
const key =
|
||||
translationKey ||
|
||||
`label_${label.toLowerCase().replace(/\s+/g, '_').replace(/[^\w]/g, '')}`;
|
||||
|
||||
const translatedLabel = t(key, label, translationParams);
|
||||
|
||||
return (
|
||||
<>
|
||||
{translatedLabel}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -198,6 +198,7 @@
|
|||
"swr": "^2.2.5",
|
||||
"tailwind-scrollbar": "^3.1.0",
|
||||
"tailwindcss": "3.4.17",
|
||||
"tailwindcss-rtl": "^0.9.0",
|
||||
"tldts": "^6.1.47",
|
||||
"tslib": "^2.3.0",
|
||||
"tweetnacl": "^1.0.3",
|
||||
|
|
|
|||
20129
pnpm-lock.yaml
20129
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue