Skip to content

Commit

Permalink
Edit community description
Browse files Browse the repository at this point in the history
  • Loading branch information
barbarah committed Sep 27, 2023
1 parent 40dfacd commit 0ca35ab
Show file tree
Hide file tree
Showing 10 changed files with 237 additions and 16 deletions.
27 changes: 25 additions & 2 deletions apps/researcher/src/app/[locale]/communities/[slug]/actions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,29 @@
'use server';

import {joinCommunity} from '@/lib/community';
import {joinCommunity, editDescription} from '@/lib/community';
import {revalidatePath} from 'next/cache';

interface editDescriptionActionProps {
communityId: string;
communitySlug: string;
description: string;
}

async function editDescriptionAction({
communityId,
communitySlug,
description,
}: editDescriptionActionProps) {
try {
await editDescription({communityId, description});
revalidatePath(`/[locale]/communities/${communitySlug}`, 'page');
revalidatePath('/[locale]/communities', 'page');

return {statusCode: 200};
} catch (err) {
return {statusCode: 500};
}
}

// Export as server actions.
export {joinCommunity};
export {joinCommunity, editDescriptionAction};
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
'use client';

import {useForm, SubmitHandler} from 'react-hook-form';
import {useTranslations} from 'next-intl';
import {useSlideOut, useNotifications} from 'ui';
import {editDescriptionAction} from './actions';

interface Props {
communityId: string;
communitySlug: string;
slideOutId: string;
description?: string;
}

interface FormValues {
description: string;
communityId: string;
communitySlug: string;
}

export default function EditDescriptionForm({
slideOutId,
communityId,
communitySlug,
description,
}: Props) {
const {
register,
handleSubmit,
setError,
formState: {errors, isSubmitting},
} = useForm({
defaultValues: {
description: description ?? '',
communityId,
communitySlug,
},
});

const t = useTranslations('Community');
const {setIsVisible} = useSlideOut();
const {addNotification} = useNotifications();

const onSubmit: SubmitHandler<FormValues> = async data => {
const response = await editDescriptionAction(data);

if (response.statusCode > 200) {
setError('root.serverError', {
message: t('serverError'),
});
} else {
addNotification({
id: 'add-object-list-success',
message: <>{t('descriptionSuccessfullyEdited')}</>,
type: 'success',
});
setIsVisible(slideOutId, false);
}
};

return (
<form
onSubmit={handleSubmit(onSubmit)}
className="flex-col gap-6 flex w-full max-w-3xl"
>
{errors.root?.serverError.message && (
<div className="rounded-md bg-red-50 p-4 mt-3">
<div className="ml-3">
<h3 className="text-sm leading-5 font-medium text-red-800">
{errors.root.serverError.message}
</h3>
</div>
</div>
)}
<div className="flex flex-col sm:flex-row gap-4 ">
<div className="flex flex-col w-full">
<label className="flex flex-col text-sm">
<strong>{t('labelDescription')}</strong>
</label>
<textarea
id="description"
{...register('description', {
maxLength: 2000,
})}
rows={4}
className="border border-greenGrey-200 rounded p-2 w-full"
/>
<p>
{errors.description && t(`description_${errors.description.type}`)}
</p>
</div>
</div>

<div className="flex flex-col lg:flex-row gap-4">
<div className="w-full lg:w-2/3 flex gap-2">
<button
disabled={isSubmitting}
type="submit"
className="p-1 sm:py-2 sm:px-3 rounded-full text-xs bg-greenGrey-100 hover:bg-greenGrey-200 transition text-greenGrey-800 flex items-center gap-1"
>
{t('changeDescriptionSaveButton')}
</button>
<button
onClick={() => setIsVisible(slideOutId, false)}
className="p-1 sm:py-2 sm:px-3 rounded-full text-xs border border-greenGrey-300 hover:bg-greenGrey-200 transition text-greenGrey-800 flex items-center gap-1"
>
{t('changeDescriptionCancelButton')}
</button>
</div>
</div>
</form>
);
}
38 changes: 30 additions & 8 deletions apps/researcher/src/app/[locale]/communities/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {revalidatePath} from 'next/cache';
import {objectList} from '@colonial-collections/database';
import ObjectCard from './object';
import AddObjectListForm from '@/components/add-object-list-form';
import {SlideOutButton, SlideOut, Notifications} from 'ui';
import {SlideOutButton, SlideOut, SlideOutClosed, Notifications} from 'ui';
import EditDescriptionForm from './edit-description-form';

interface Props {
params: {
Expand All @@ -20,6 +21,11 @@ interface Props {
}

const slideOutFormId = 'add-object-list';
const slideOutDescriptionId = 'edit-community-description';

// Don't cache this page, so we always get the latest community data from the third-party Clerk.
// With 'force-no-store', the description will change after editing.
export const fetchCache = 'force-no-store';

export default async function CommunityPage({params}: Props) {
const t = await getTranslator(params.locale, 'Community');
Expand Down Expand Up @@ -87,14 +93,30 @@ export default async function CommunityPage({params}: Props) {
{community.name}
</span>
</h1>

<div className="w-full flex flex-col md:flex-row justify-center px-4">
<div className="mb-4 max-w-3xl text-left">
{/*Place the description here*/}
</div>
<div className="flex flex-col items-start md:justify-center md:items-center w-full mb-4">
<JoinCommunityButton communityId={community.id} />
</div>
<SlideOutClosed id={slideOutDescriptionId}>
<div className="mb-4 max-w-3xl text-left whitespace-pre-line">
{community.publicMetadata?.description}
</div>
</SlideOutClosed>
<SlideOut id={slideOutDescriptionId}>
<EditDescriptionForm
slideOutId={slideOutDescriptionId}
communityId={community.id}
communitySlug={community.slug!}
description={community.publicMetadata?.description}
/>
</SlideOut>
</div>
<div className="flex flex-col items-start md:justify-center md:items-center w-full mb-4">
<JoinCommunityButton communityId={community.id} />
<SlideOutButton
hideIfOpen
id={slideOutDescriptionId}
className="flex items-center py-2 px-3 rounded-full bg-sand-100 text-sand-900 hover:bg-white transition text-xs"
>
{t('editDescriptionButton')}
</SlideOutButton>
</div>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ export default function CommunityCard({community, locale}: CommunityCardProps) {
),
})}
</h1>
<div className="text-center p-4">
{/* TODO add community description */}
<div className="text-center m-4 line-clamp-3">
{community.publicMetadata?.description}
</div>

<div className="flex border-stone-300 border-t text-sm text-stone-600">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export async function addList(
try {
await objectList.createListForCommunity(listItem);
const community = await getCommunityById(listItem.communityId);
revalidatePath(`/[locale]/communities/${community.slug}`);
revalidatePath(`/[locale]/communities/${community.slug}`, 'page');

return {statusCode: 200};
} catch (err) {
Expand Down
20 changes: 20 additions & 0 deletions apps/researcher/src/lib/community.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,34 +101,39 @@ describe('sort', () => {
slug: 'community-2',
imageUrl: 'https://example.com/image.png',
createdAt: 1690000000000,
publicMetadata: null,
},
{
id: 'community1',
name: 'Community 1',
slug: 'community-1',
imageUrl: 'https://example.com/image.png',
createdAt: 1600000000000,
publicMetadata: null,
},
{
id: 'community4',
name: 'Community 4',
slug: 'community-4',
imageUrl: 'https://example.com/image.png',
createdAt: 1680000000000,
publicMetadata: null,
},
{
id: 'community3',
name: 'Community 3',
slug: 'community-3',
imageUrl: 'https://example.com/image.png',
createdAt: 1650000000000,
publicMetadata: null,
},
{
id: 'community5',
name: 'Community 5',
slug: 'community-5',
imageUrl: 'https://example.com/image.png',
createdAt: 1670000000000,
publicMetadata: null,
},
];

Expand All @@ -142,34 +147,39 @@ describe('sort', () => {
slug: 'community-1',
imageUrl: 'https://example.com/image.png',
createdAt: 1600000000000,
publicMetadata: null,
},
{
id: 'community2',
name: 'Community 2',
slug: 'community-2',
imageUrl: 'https://example.com/image.png',
createdAt: 1690000000000,
publicMetadata: null,
},
{
id: 'community3',
name: 'Community 3',
slug: 'community-3',
imageUrl: 'https://example.com/image.png',
createdAt: 1650000000000,
publicMetadata: null,
},
{
id: 'community4',
name: 'Community 4',
slug: 'community-4',
imageUrl: 'https://example.com/image.png',
createdAt: 1680000000000,
publicMetadata: null,
},
{
id: 'community5',
name: 'Community 5',
slug: 'community-5',
imageUrl: 'https://example.com/image.png',
createdAt: 1670000000000,
publicMetadata: null,
},
];

Expand All @@ -186,34 +196,39 @@ describe('sort', () => {
slug: 'community-5',
imageUrl: 'https://example.com/image.png',
createdAt: 1670000000000,
publicMetadata: null,
},
{
id: 'community4',
name: 'Community 4',
slug: 'community-4',
imageUrl: 'https://example.com/image.png',
createdAt: 1680000000000,
publicMetadata: null,
},
{
id: 'community3',
name: 'Community 3',
slug: 'community-3',
imageUrl: 'https://example.com/image.png',
createdAt: 1650000000000,
publicMetadata: null,
},
{
id: 'community2',
name: 'Community 2',
slug: 'community-2',
imageUrl: 'https://example.com/image.png',
createdAt: 1690000000000,
publicMetadata: null,
},
{
id: 'community1',
name: 'Community 1',
slug: 'community-1',
imageUrl: 'https://example.com/image.png',
createdAt: 1600000000000,
publicMetadata: null,
},
];

Expand All @@ -230,34 +245,39 @@ describe('sort', () => {
slug: 'community-2',
imageUrl: 'https://example.com/image.png',
createdAt: 1690000000000,
publicMetadata: null,
},
{
id: 'community4',
name: 'Community 4',
slug: 'community-4',
imageUrl: 'https://example.com/image.png',
createdAt: 1680000000000,
publicMetadata: null,
},
{
id: 'community5',
name: 'Community 5',
slug: 'community-5',
imageUrl: 'https://example.com/image.png',
createdAt: 1670000000000,
publicMetadata: null,
},
{
id: 'community3',
name: 'Community 3',
slug: 'community-3',
imageUrl: 'https://example.com/image.png',
createdAt: 1650000000000,
publicMetadata: null,
},
{
id: 'community1',
name: 'Community 1',
slug: 'community-1',
imageUrl: 'https://example.com/image.png',
createdAt: 1600000000000,
publicMetadata: null,
},
];

Expand Down
Loading

0 comments on commit 0ca35ab

Please sign in to comment.