Skip to content

Commit

Permalink
Resolve "Creating Posts - add missing functionality"
Browse files Browse the repository at this point in the history
  • Loading branch information
KKocot authored and func0x committed Mar 27, 2024
1 parent f931fb1 commit 98b40b8
Show file tree
Hide file tree
Showing 14 changed files with 292 additions and 52 deletions.
10 changes: 2 additions & 8 deletions apps/blog/components/community-description.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { cn } from '@ui/lib/utils';
import { Card, CardContent, CardHeader, CardTitle } from '@hive/ui/components/card';
import Link from 'next/link';
import { Button } from '@ui/components/button';
import ln2list from '@/blog/lib/ln2list';
import { type Community, type Subscription, IAccountNotification } from '@transaction/lib/bridge';
import { SubsListDialog } from './subscription-list-dialog';
Expand All @@ -12,6 +11,7 @@ import { useUser } from '@smart-signer/lib/auth/use-user';
import { useContext } from 'react';
import { HiveRendererContext } from './hive-renderer-context';
import SubscribeCommunity from './subscribe-community';
import NewPost from './new_post_button';

const CommunityDescription = ({
data,
Expand Down Expand Up @@ -64,13 +64,7 @@ const CommunityDescription = ({
</div>
<div className="my-4 flex flex-col gap-2">
<SubscribeCommunity user={user} username={username} subStatus={data.context.subscribed} />
<Button
size="sm"
className="w-full bg-blue-800 text-center hover:bg-blue-900"
data-testid="community-new-post-button"
>
<Link href={`submit.html?category=${data.name}`}>{t('communities.buttons.new_post')}</Link>
</Button>
<NewPost name={data.name} />
</div>
<div data-testid="community-leadership" className="my-6 flex flex-col">
<h6 className="my-1.5 font-semibold leading-none tracking-tight">
Expand Down
8 changes: 2 additions & 6 deletions apps/blog/components/community-simple-description.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { Card, CardContent, CardHeader, CardTitle } from '@ui/components/card';
import Link from 'next/link';
import { Button } from '@hive/ui/components/button';
import type { Community, Subscription } from '@transaction/lib/bridge';
import { IAccountNotification } from '@transaction/lib/bridge';
import { SubsListDialog } from './subscription-list-dialog';
import { ActivityLogDialog } from './activity-log-dialog';
import { useTranslation } from 'next-i18next';
import SubscribeCommunity from './subscribe-community';
import { useUser } from '@smart-signer/lib/auth/use-user';
import NewPost from './new_post_button';

const CommunitySimpleDescription = ({
data,
Expand Down Expand Up @@ -52,10 +51,7 @@ const CommunitySimpleDescription = ({
<CardContent className="col-span-1 flex items-center justify-center p-0">
<div className="my-4 flex flex-col gap-4">
<SubscribeCommunity user={user} username={username} subStatus={data.context.subscribed} />

<Button size="sm" className="hover: w-full bg-blue-800 text-center">
<Link href={`/submit.html?category=${data.name}`}>{t('communities.buttons.new_post')}</Link>
</Button>
<NewPost name={data.name} />
</div>
</CardContent>
</Card>
Expand Down
37 changes: 37 additions & 0 deletions apps/blog/components/new_post_button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useLocalStorage } from '@smart-signer/lib/use-local-storage';
import { Button } from '@ui/components';
import { useTranslation } from 'next-i18next';
import Link from 'next/link';

type AccountFormValues = {
title: string;
postArea: string;
postSummary: string;
tags: string;
author: string;
category: string;
};
const defaultValues = {
title: '',
postArea: '',
postSummary: '',
tags: '',
author: '',
category: ''
};
const NewPost = ({ name }: { name: string }) => {
const { t } = useTranslation('common_blog');
const [storedPost, storePost] = useLocalStorage<AccountFormValues>('postData', defaultValues);

return (
<Button
size="sm"
className="w-full bg-blue-800 text-center hover:bg-blue-900"
onClick={() => storePost({ ...storedPost, tags: name, category: name })}
data-testid="community-new-post-button"
>
<Link href={`/submit.html?category=${name}`}>{t('communities.buttons.new_post')}</Link>
</Button>
);
};
export default NewPost;
91 changes: 76 additions & 15 deletions apps/blog/components/post-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { useQuery } from '@tanstack/react-query';
import { getSubscriptions } from '@transaction/lib/bridge';
import { useRouter } from 'next/router';
import { hiveChainService } from '@transaction/lib/hive-chain-service';
import { TFunction } from 'i18next';

const defaultValues = {
title: '',
Expand All @@ -41,6 +42,55 @@ const defaultValues = {
payoutType: '50%'
};

const MAX_TAGS = 8;
function validateTagInput(value: string, required = true, t: TFunction<'common_wallet', undefined>) {
if (!value || value.trim() === '') return required ? t('g.required') : null;
const tags = value.trim().replace(/#/g, '').split(/ +/);
return tags.length > MAX_TAGS
? t('submit_page.category_selector.use_limited_amount_of_categories', {
amount: MAX_TAGS
})
: tags.find((c) => c.length > 24)
? t('submit_page.category_selector.maximum_tag_length_is_24_characters')
: tags.find((c) => c.split('-').length > 2)
? t('submit_page.category_selector.use_one_dash')
: tags.find((c) => c.indexOf(',') >= 0)
? t('submit_page.category_selector.use_spaces_to_separate_tags')
: tags.find((c) => /[A-Z]/.test(c))
? t('submit_page.category_selector.use_only_lowercase_letters')
: tags.find((c) => !/^[a-z0-9-#]+$/.test(c))
? t('submit_page.category_selector.use_only_allowed_characters')
: tags.find((c) => !/^[a-z-#]/.test(c))
? t('submit_page.category_selector.must_start_with_a_letter')
: tags.find((c) => !/[a-z0-9]$/.test(c))
? t('submit_page.category_selector.must_end_with_a_letter_or_number')
: tags.filter((c) => c.substring(0, 5) === 'hive-').length > 1
? t('submit_page.category_selector.must_not_include_hivemind_community_owner')
: tags.reduce((acc, tag, index, array) => {
const isDuplicate = array.slice(index + 1).some((b) => b === tag);
return acc || isDuplicate;
}, false)
? t('submit_page.category_selector.tags_cannot_be_repeated')
: null;
}

function validateSummoryInput(value: string, t: TFunction<'common_wallet', undefined>) {
const markdownRegex = /(?:\*[\w\s]*\*|#[\w\s]*#|_[\w\s]*_|~[\w\s]*~|\]\s*\(|\]\s*\[)/;
const htmlTagRegex = /<\/?[\w\s="/.':;#-/?]+>/gi;
return markdownRegex.test(value)
? t('submit_page.markdown_not_supported')
: htmlTagRegex.test(value)
? t('submit_page.html_not_supported')
: null;
}

function validateAltUsernameInput(value: string, t: TFunction<'common_wallet', undefined>) {
const altAuthorAllowedCharactersRegex = /^[\w.\d-]+$/;
return value !== '' && !altAuthorAllowedCharactersRegex.test(value)
? t('submit_page.must_contain_only')
: null;
}

export default function PostForm({ username }: { username: string }) {
const { hiveRenderer } = useContext(HiveRendererContext);
const router = useRouter();
Expand All @@ -57,19 +107,13 @@ export default function PostForm({ username }: { username: string }) {
} = useQuery([['subscriptions', username]], () => getSubscriptions(username), {
enabled: Boolean(username)
});

const accountFormSchema = z.object({
title: z.string().min(2, t('submit_page.string_must_contain', { num: 2 })),
postArea: z.string().min(1, t('submit_page.string_must_contain', { num: 1 })),
postSummary: z.string().max(140),
tags: z
.string()
.refine((v) => !((v.match(/hive-/g) || []).length > 1), {
message: t('submit_page.to_many_communities')
})
.refine((v) => v.split(/\s+/).length <= 8, {
message: t('submit_page.to_many_tags')
}),
author: z.string().regex(/^$|^[[a-zAZ1-9]+$/, t('submit_page.must_contain_only')),
postSummary: z.string().max(140, t('submit_page.maximum_characters', { num: 140 })),
tags: z.string(),
author: z.string().max(50, t('submit_page.maximum_characters', { num: 50 })),
category: z.string(),
beneficiaries: z.array(
z.object({
Expand Down Expand Up @@ -98,6 +142,9 @@ export default function PostForm({ username }: { username: string }) {
values: getValues(storedPost)
});
const watchedValues = form.watch();
const tagsCheck = validateTagInput(watchedValues.tags, false, t);
const summaryCheck = validateSummoryInput(watchedValues.postSummary, t);
const altUsernameCheck = validateAltUsernameInput(watchedValues.author, t);

useEffect(() => {
storePost(watchedValues);
Expand All @@ -111,10 +158,9 @@ export default function PostForm({ username }: { username: string }) {

createPostPermlink();
}, [username, storedPost?.title]);

async function onSubmit(data: AccountFormValues) {
const chain = await hiveChainService.getHiveChain();
const tags = storedPost?.tags.split(' ') ?? [];
const tags = storedPost?.tags.replace(/#/g, '').split(' ') ?? [];
const maxAcceptedPayout = await chain.hbd(Number(storedPost.maxAcceptedPayout));
try {
await transactionService.post(
Expand Down Expand Up @@ -153,6 +199,7 @@ export default function PostForm({ username }: { username: string }) {
{sideBySide ? t('submit_page.disable_side') : t('submit_page.enable_side')}
</h1>
<Button
type="button"
onClick={() => setPreview((prev) => !prev)}
variant="link"
className="hover:text-destructive"
Expand Down Expand Up @@ -186,7 +233,7 @@ export default function PostForm({ username }: { username: string }) {
/>
</FormControl>
<FormDescription className="border-x-2 border-b-2 border-border px-3 pb-1 text-xs text-destructive">
{t('submit_page.insert_images_by_dragging')},
{t('submit_page.insert_images_by_dragging')}
<span>
<Label className="cursor-pointer text-red-500" htmlFor="picture">
{t('submit_page.selecting_them')}
Expand All @@ -207,6 +254,8 @@ export default function PostForm({ username }: { username: string }) {
<FormControl>
<Input placeholder={t('submit_page.post_summary')} {...field} />
</FormControl>
<div className="text-xs text-red-500">{summaryCheck}</div>

<FormMessage />
</FormItem>
)}
Expand All @@ -219,6 +268,7 @@ export default function PostForm({ username }: { username: string }) {
<FormControl>
<Input placeholder={t('submit_page.enter_your_tags')} {...field} />
</FormControl>
<div className="text-xs text-red-500">{tagsCheck}</div>
<FormMessage />
</FormItem>
)}
Expand All @@ -231,6 +281,7 @@ export default function PostForm({ username }: { username: string }) {
<FormControl>
<Input placeholder={t('submit_page.author_if_different')} {...field} />
</FormControl>
<div className="text-xs text-red-500">{altUsernameCheck}</div>
<FormMessage />
</FormItem>
)}
Expand All @@ -242,7 +293,10 @@ export default function PostForm({ username }: { username: string }) {
{storedPost?.payoutType === '100%' ? t('submit_page.power_up') : ' 50% HBD / 50% HP'}
</span>
<AdvancedSettingsPostForm username={username} onChangeStore={storePost} data={storedPost}>
<span className="cursor-pointer text-xs text-destructive">
<span
className="cursor-pointer text-xs text-destructive"
title={t('submit_page.advanced_tooltip')}
>
{t('submit_page.advanced_settings')}
</span>
</AdvancedSettingsPostForm>
Expand All @@ -262,6 +316,7 @@ export default function PostForm({ username }: { username: string }) {
{t('submit_page.posting_to')}
<FormControl>
<Select
defaultValue={storedPost ? storedPost.category : 'blog'}
onValueChange={(e) => storePost({ ...storedPost, tags: e + ' ' + storedPost.tags })}
>
<FormControl>
Expand All @@ -286,7 +341,13 @@ export default function PostForm({ username }: { username: string }) {
<Button
type="submit"
variant="redHover"
disabled={!storedPost?.title || storedPost.tags.length === 0}
disabled={
!storedPost?.title ||
storedPost.tags.length === 0 ||
Boolean(tagsCheck) ||
Boolean(summaryCheck) ||
Boolean(altUsernameCheck)
}
>
{t('submit_page.submit')}
</Button>
Expand Down
20 changes: 18 additions & 2 deletions apps/blog/locales/en/common_blog.json
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,6 @@
}
},
"submit_page": {
"to_many_communities": "Too much community",
"to_many_tags": "Too many tags",
"disable_side": "Disable side-by-side editor",
"enable_side": "Enable side-by-side editor",
"string_must_contain": "String must contain at least {{num}} character(s)",
Expand All @@ -412,6 +410,10 @@
"clean": "Clean",
"markdown_styling_guide": "Markdown Styling Guide",
"power_up": " Power up 100%",
"maximum_characters": "Maximum {{num}} characters",
"markdown_not_supported": "Markdown is not supported here",
"html_not_supported": "HTML is not supported here",
"advanced_tooltip": "Here you can set post options such as author rewards split, max accepted payout, beneficiaries & post templates",
"advanced_settings_dialog": {
"changes_saved": "Changes saved",
"advanced_settings": "Advanced settings",
Expand All @@ -438,6 +440,20 @@
"template_name_is_taken": "Template name is taken",
"save": "Save",
"delete_template": "Delete Template"
},
"category_selector": {
"tag_your_story": "Tag (up to 8 tags), the first tag is your main category.",
"select_a_tag": "Select a tag",
"maximum_tag_length_is_24_characters": "Maximum tag length is 24 characters",
"use_limited_amount_of_categories": "Please use only {{amount}} tags",
"use_only_lowercase_letters": "Use only lowercase letters",
"use_one_dash": "Use only one dash",
"use_spaces_to_separate_tags": "Use spaces to separate tags",
"use_only_allowed_characters": "Use only lowercase letters, digits and one dash",
"must_start_with_a_letter": "Must start with a letter",
"must_end_with_a_letter_or_number": "Must end with a letter or number",
"must_not_include_hivemind_community_owner": "Post already has hive tag by default, please do not include another 'hive-' tag.",
"tags_cannot_be_repeated": "Tags cannot be repeated"
}
},
"search_page": {
Expand Down
20 changes: 18 additions & 2 deletions apps/blog/locales/es/common_blog.json
Original file line number Diff line number Diff line change
Expand Up @@ -374,8 +374,6 @@
}
},
"submit_page": {
"to_many_communities": "Demasiada comunidad",
"to_many_tags": "Demasiadas etiquetas",
"disable_side": "Deshabilitar el editor en paralelo",
"enable_side": "Habilitar el editor en paralelo",
"string_must_contain": "La cadena debe contener al menos {{num}} caracteres",
Expand All @@ -400,6 +398,10 @@
"clean": "Limpiar",
"markdown_styling_guide": "Guía de Estilo Markdown",
"power_up": "Potenciar al 100%",
"maximum_characters": "Máximo de {{num}} caracteres",
"markdown_not_supported": "Markdown no es compatible aquí",
"html_not_supported": "HTML no es compatible aquí",
"advanced_tooltip": "Aquí puedes establecer opciones de publicación como la división de recompensas del autor, el pago máximo aceptado, los beneficiarios y las plantillas de publicación",
"advanced_settings_dialog": {
"changes_saved": "Cambios guardados",
"advanced_settings": "Configuración avanzada",
Expand All @@ -426,6 +428,20 @@
"template_name_is_taken": "El nombre de la plantilla ya está en uso",
"save": "Guardar",
"delete_template": "Eliminar plantilla"
},
"category_selector": {
"tag_your_story": "Etiqueta (hasta 5 etiquetas), la primera etiqueta es tu principal categoría.",
"select_a_tag": "Selecciona una etiqueta",
"maximum_tag_length_is_24_characters": "La longitud máxima de la etiqueta es de 24 caracteres",
"use_limited_amount_of_categories": "Por favor usa sólo {{amount}} categorías",
"use_only_lowercase_letters": "Usa sólo letras minúsculas",
"use_one_dash": "Usa sólo un guión",
"use_spaces_to_separate_tags": "Usa espacios para separar las etiquetas",
"use_only_allowed_characters": "Usa sólo letras minúsculas, dígitos y un guión",
"must_start_with_a_letter": "Debe empezar con una letra",
"must_end_with_a_letter_or_number": "Debe terminar con una letra o número",
"must_not_include_hivemind_community_owner": "La publicación ya tiene la etiqueta 'hive' por defecto, por favor no incluya otra etiqueta 'hive-'",
"tags_cannot_be_repeated": "Las etiquetas no pueden repetirse"
}
},
"search_page": {
Expand Down
Loading

0 comments on commit 98b40b8

Please sign in to comment.