Skip to content

Commit

Permalink
Merge pull request #274 from colonial-heritage/communityDescription
Browse files Browse the repository at this point in the history
Community description
  • Loading branch information
barbarah authored Oct 20, 2023
2 parents 4a7021e + ed42d00 commit 4e069ef
Show file tree
Hide file tree
Showing 10 changed files with 402 additions and 145 deletions.
36 changes: 33 additions & 3 deletions apps/researcher/src/app/[locale]/communities/[slug]/actions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,36 @@
'use server';

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

// Export as server actions.
export {joinCommunity};
interface UpdateDescriptionAndRevalidateProps {
communityId: string;
communitySlug: string;
description: string;
}

export async function updateDescriptionAndRevalidate({
communityId,
communitySlug,
description,
}: UpdateDescriptionAndRevalidateProps) {
await updateDescription({communityId, description});
revalidatePath(`/[locale]/communities/${communitySlug}`, 'page');
revalidatePath('/[locale]/communities', 'page');
}

interface JoinCommunityAndRevalidateProps {
communityId: string;
communitySlug: string;
userId: string;
}

export async function joinCommunityAndRevalidate({
communityId,
communitySlug,
userId,
}: JoinCommunityAndRevalidateProps) {
await joinCommunity({communityId, userId});
revalidatePath(`/[locale]/communities/${communitySlug}`, 'page');
revalidatePath('/[locale]/communities', 'page');
}
10 changes: 6 additions & 4 deletions apps/researcher/src/app/[locale]/communities/[slug]/buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import {useState} from 'react';
import {useTranslations} from 'next-intl';
import {useClerk, useUser} from '@clerk/nextjs';
import {useTransition} from 'react';
import {joinCommunity} from './actions';
import {joinCommunityAndRevalidate} from './actions';

interface Props {
communityId: string;
communitySlug: string;
}

// If logged in and not part of the community, show the join button
export function JoinCommunityButton({communityId}: Props) {
export function JoinCommunityButton({communityId, communitySlug}: Props) {
const {isLoaded, isSignedIn, user} = useUser();
const [isClicked, setIsClicked] = useState(false);
const [hasError, setHasError] = useState(false);
Expand All @@ -34,8 +35,9 @@ export function JoinCommunityButton({communityId}: Props) {
setIsClicked(true);
startTransition(async () => {
try {
await joinCommunity({
organizationId: communityId,
await joinCommunityAndRevalidate({
communityId,
communitySlug,
userId: user!.id,
});
} catch (err) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
'use client';

import {useForm, SubmitHandler} from 'react-hook-form';
import {useTranslations} from 'next-intl';
import {useSlideOut, useNotifications} from 'ui';
import {updateDescriptionAndRevalidate} 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 descriptionFormValues => {
try {
await updateDescriptionAndRevalidate(descriptionFormValues);
addNotification({
id: 'add-object-list-success',
message: <>{t('descriptionUpdated')}</>,
type: 'success',
});
setIsVisible(slideOutId, false);
} catch (err) {
setError('root.serverError', {
message: t('serverError'),
});
}
};

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>
);
}
48 changes: 36 additions & 12 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-dynamic', the description in the Clerk metadata will change after editing.
export const dynamic = 'force-dynamic';

export default async function CommunityPage({params}: Props) {
const t = await getTranslator(params.locale, 'Community');
Expand Down Expand Up @@ -87,14 +93,33 @@ 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.description}
</div>
</SlideOutClosed>
<SlideOut id={slideOutDescriptionId}>
<EditDescriptionForm
slideOutId={slideOutDescriptionId}
communityId={community.id}
communitySlug={community.slug!}
description={community.description}
/>
</SlideOut>
</div>
<div className="flex flex-col items-start md:justify-center md:items-center w-full mb-4">
<JoinCommunityButton
communityId={community.id}
communitySlug={params.slug}
/>
<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 Expand Up @@ -166,9 +191,9 @@ export default async function CommunityPage({params}: Props) {
key={membership.id}
>
<div className="w-10">
{membership.publicUserData?.profileImageUrl && (
{membership.imageUrl && (
<Image
src={membership.publicUserData.profileImageUrl}
src={membership.imageUrl}
alt=""
className="w-full rounded-full"
width={40}
Expand All @@ -178,8 +203,7 @@ export default async function CommunityPage({params}: Props) {
</div>
<div className="flex flex-col">
<div className="">
{membership.publicUserData?.firstName}{' '}
{membership.publicUserData?.lastName}
{membership.firstName} {membership.lastName}
</div>
<div className="text-neutral-600">
{/* Place country name here */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export default function CommunityCard({community, locale}: CommunityCardProps) {
return (
<Link
href={`/communities/${community.slug}`}
className="rounded-lg mb-20 bg-[#f3eee2] hover:bg-[#f1e9d7] text-stone-800 transition"
className="rounded-lg mb-20 bg-[#f3eee2] hover:bg-[#f1e9d7] text-stone-800 transition flex flex-col"
>
<div className="-mt-20 w-full flex justify-center">
<Image
Expand All @@ -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 grow">
{community.description}
</div>

<div className="flex border-stone-300 border-t text-sm text-stone-600">
Expand Down
Loading

2 comments on commit 4e069ef

@vercel
Copy link

@vercel vercel bot commented on 4e069ef Oct 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 4e069ef Oct 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.