diff --git a/package.json b/package.json index 70f2c6e..128a95d 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "private": true, "type": "module", "scripts": { - "dev": "next dev --turbo", + "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint", diff --git a/src/app/[locale]/(main)/community/[communityId]/admin/page.client.tsx b/src/app/[locale]/(main)/community/[communityId]/admin/page.client.tsx new file mode 100644 index 0000000..fa1a4cf --- /dev/null +++ b/src/app/[locale]/(main)/community/[communityId]/admin/page.client.tsx @@ -0,0 +1,58 @@ +'use client' +import { Community } from '@/utils/types/models' +import { TabsContent } from '@/components/ui/tabs' +import CommunityAdminMain from '@/components/community/admin/main' +import MyCommunities from '@/components/community/myCommunities' +import { functions } from '@/app/appwrite-client' +import { ExecutionMethod } from 'node-appwrite' +import { useEffect, useState } from 'react' +import NoAccess from '@/components/static/noAccess' +import { hasAdminPanelAccess } from '@/utils/actions/community/checkRoles' +import { toast } from 'sonner' + +export default function PageClient({ + community, +}: { + community: Community.CommunityDocumentsType +}) { + const [hasPermission, setHasPermission] = useState(false) + const [isLoading, setIsLoading] = useState(true) + + const getOwnerStatus = async () => { + const data = await functions.createExecution( + 'community-endpoints', + '', + false, + `/community/isFollowing?communityId=${community.$id}`, + ExecutionMethod.GET + ) + + const response = JSON.parse(data.responseBody) + + if (response.code === 500) { + toast.error('Error fetching community data. Please try again later.') + } + + setHasPermission(await hasAdminPanelAccess(response.roles)) + } + + useEffect(() => { + getOwnerStatus().then(() => setIsLoading(false)) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [community]) + + if (!isLoading && !hasPermission) { + return + } + + return ( + <> + + + + + + + + ) +} diff --git a/src/app/[locale]/(main)/community/[communityId]/admin/page.tsx b/src/app/[locale]/(main)/community/[communityId]/admin/page.tsx new file mode 100644 index 0000000..a229ce3 --- /dev/null +++ b/src/app/[locale]/(main)/community/[communityId]/admin/page.tsx @@ -0,0 +1,54 @@ +import PageLayout from '@/components/pageLayout' +import { getCommunity } from '@/utils/server-api/communities/getCommunity' +import { notFound } from 'next/navigation' +import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs' +import PageClient from './page.client' + +export const runtime = 'edge' + +export async function generateMetadata({ + params: { communityId }, +}: { + params: { communityId: string } +}) { + const community = await getCommunity(communityId) + + if (!community.$id) { + return notFound() + } + + return { + title: community?.name || 'Community Admin', + description: community?.description, + icons: { + icon: '/logos/Headpat_Logo_web_1024x1024_240518-02.png', + }, + openGraph: { + title: community?.name || 'Community Admin', + description: community?.description, + images: '/logos/Headpat_Logo_web_1024x1024_240518-02.png', + }, + } +} + +export default async function Page({ + params: { communityId }, +}: { + params: { communityId: string } +}) { + const community = await getCommunity(communityId) + + return ( + + +
+ + General + Settings + +
+ +
+
+ ) +} diff --git a/src/app/[locale]/(main)/community/[communityId]/followers/page.client.tsx b/src/app/[locale]/(main)/community/[communityId]/followers/page.client.tsx index f8cb19c..7edd539 100644 --- a/src/app/[locale]/(main)/community/[communityId]/followers/page.client.tsx +++ b/src/app/[locale]/(main)/community/[communityId]/followers/page.client.tsx @@ -40,7 +40,7 @@ export default function PageClient({ communityId }: { communityId: string }) { if (isFetching || !followers) { return ( - +

Loading...

@@ -52,7 +52,7 @@ export default function PageClient({ communityId }: { communityId: string }) { if (followers.length === 0) { return ( - +

No followers found

diff --git a/src/app/[locale]/(main)/community/[communityId]/page.client.tsx b/src/app/[locale]/(main)/community/[communityId]/page.client.tsx index c1390d9..2238a03 100644 --- a/src/app/[locale]/(main)/community/[communityId]/page.client.tsx +++ b/src/app/[locale]/(main)/community/[communityId]/page.client.tsx @@ -20,19 +20,18 @@ import { CardHeader, CardTitle, } from '@/components/ui/card' -import { Link } from '@/navigation' +import { Link, useRouter } from '@/navigation' import { Separator } from '@/components/ui/separator' import PageLayout from '@/components/pageLayout' import { Community } from '@/utils/types/models' +import { hasAdminPanelAccess } from '@/utils/actions/community/checkRoles' export default function PageClient({ communityId, communityData, - userSelf, }: { communityId: string communityData: Community.CommunityDocumentsType - userSelf: any }) { const [community, setCommunity] = useState(communityData) @@ -167,7 +166,9 @@ export default function PageClient({ export function FollowerButton({ displayName, communityId }) { const [isFollowingState, setIsFollowingState] = useState(null) + const [hasPermissions, setHasPermissions] = useState(false) const [isLoading, setIsLoading] = useState(true) + const router = useRouter() const getIsFollowing = async () => { try { @@ -180,7 +181,9 @@ export function FollowerButton({ displayName, communityId }) { ) const response = JSON.parse(data.responseBody) - setIsFollowingState(response) + + setIsFollowingState(response.isFollowing) + setHasPermissions(await hasAdminPanelAccess(response.roles)) } catch (error) { // Do nothing } @@ -200,6 +203,7 @@ export function FollowerButton({ displayName, communityId }) { ExecutionMethod.POST ) const response = JSON.parse(data.responseBody) + if (response.code === 400) { return toast.error('Community ID is missing. Please try again later.') } else if (response.code === 401) { @@ -222,7 +226,7 @@ export function FollowerButton({ displayName, communityId }) { ExecutionMethod.DELETE ) const response = JSON.parse(data.responseBody) - console.log(response) + if (response.type === 'community_unfollow_missing_id') { return toast.error('Community ID is missing. Please try again later.') } else if (response.type === 'community_unfollow_owner') { @@ -240,13 +244,28 @@ export function FollowerButton({ displayName, communityId }) { } } + const handleManage = () => { + router.push({ + pathname: `/community/[communityId]/admin`, + params: { communityId: communityId }, + }) + } + return ( <> {isLoading ? ( ) : ( - )} diff --git a/src/app/[locale]/(main)/community/[communityId]/page.tsx b/src/app/[locale]/(main)/community/[communityId]/page.tsx index ab4dbbe..54e337b 100644 --- a/src/app/[locale]/(main)/community/[communityId]/page.tsx +++ b/src/app/[locale]/(main)/community/[communityId]/page.tsx @@ -1,5 +1,4 @@ import { getCommunity } from '@/utils/server-api/communities/getCommunity' -import { getUser } from '@/utils/server-api/account/user' import PageClient from './page.client' import { notFound } from 'next/navigation' @@ -37,18 +36,5 @@ export default async function Page({ }) { const community = await getCommunity(communityId) - let userSelf = null - try { - userSelf = await getUser() - } catch (error) { - // Do nothing - } - - return ( - - ) + return } diff --git a/src/app/[locale]/(main)/users/page.client.tsx b/src/app/[locale]/(main)/users/page.client.tsx index e09546c..eb4b2dd 100644 --- a/src/app/[locale]/(main)/users/page.client.tsx +++ b/src/app/[locale]/(main)/users/page.client.tsx @@ -27,9 +27,14 @@ export default function ClientPage() { ) const response = JSON.parse(data.responseBody) + + if (response.code === 500) { + toast.error('Failed to fetch users. Please try again later.') + return + } setUsers(response.documents) } catch (error) { - toast('Failed to fetch users. Please try again later.') + toast.error('Failed to fetch users. Please try again later.') } finally { setIsFetching(false) } diff --git a/src/components/account/views/general.tsx b/src/components/account/views/general.tsx index e338075..adcbd68 100644 --- a/src/components/account/views/general.tsx +++ b/src/components/account/views/general.tsx @@ -48,6 +48,7 @@ export default function GeneralAccountView({ getDocument('hp_db', 'userdata', accountData.$id) .then((data: UserData.UserDataDocumentsType) => setUserData(data)) .catch(() => { + // Sometimes the function is too slow and the data is not created yet window.location.reload() }) }, [accountData]) diff --git a/src/components/community/addCommunity.tsx b/src/components/community/addCommunity.tsx index c9ea880..2302b9f 100644 --- a/src/components/community/addCommunity.tsx +++ b/src/components/community/addCommunity.tsx @@ -2,7 +2,6 @@ import { AlertDialog, - AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, @@ -19,7 +18,7 @@ import { Switch } from '@/components/ui/switch' import { z } from 'zod' import { toast } from 'sonner' import { Button } from '@/components/ui/button' -import { AppwriteException, ExecutionMethod, Models } from 'node-appwrite' +import { ExecutionMethod, Models } from 'node-appwrite' import { functions } from '@/app/appwrite-client' import { useRouter } from '@/navigation' import { HeadpatException } from '@/utils/types/models' @@ -129,6 +128,7 @@ export default function AddCommunity({ maxLength={4096} rows={8} value={communityData.description} + className="resize-none" onChange={(e) => setCommunityData((prev) => ({ ...prev, diff --git a/src/components/community/admin/main.tsx b/src/components/community/admin/main.tsx new file mode 100644 index 0000000..1f5db4f --- /dev/null +++ b/src/components/community/admin/main.tsx @@ -0,0 +1,146 @@ +'use client' +import { Community } from '@/utils/types/models' +import { databases, functions } from '@/app/appwrite-client' +import { ExecutionMethod } from 'node-appwrite' +import { useEffect, useState } from 'react' +import NoAccess from '@/components/static/noAccess' +import UploadAvatar from '@/components/community/uploadAvatar' +import UploadBanner from '@/components/community/uploadBanner' +import { Label } from '@/components/ui/label' +import { Input } from '@/components/ui/input' +import { Button } from '@/components/ui/button' +import { z } from 'zod' +import { Textarea } from '@/components/ui/textarea' + +const communitySchema = z.object({ + name: z + .string() + .min(4, 'Name must be 4 characters or more') + .max(64, 'Name must be 64 characters or less'), + description: z + .string() + .max(4096, 'Description must be 4096 characters or less'), + status: z.string().max(24, 'Status must be 24 characters or less'), +}) + +export default function CommunityAdminMain({ + community, +}: { + community: Community.CommunityDocumentsType +}) { + const [isLoading, setIsLoading] = useState(true) + const [communityData, setCommunityData] = + useState(null) + const [isUploading, setIsUploading] = useState(false) + + const getCommunity = async () => { + const data: Community.CommunityDocumentsType = await databases.getDocument( + 'hp_db', + 'community', + community.$id + ) + setCommunityData(data) + } + + useEffect(() => { + getCommunity().then(() => setIsLoading(false)) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [community]) + + const handleSubmit = async (e) => { + e.preventDefault() + } + + return isLoading ? ( +
Loading...
+ ) : ( + <> +
+
+
+

+ Frontpage Settings +

+

+ Here you can change your public profile settings. +

+
+ +
+ +
+ + +
+
+ +
+ { + if (e.target.value.length <= 32) { + setCommunityData({ + ...communityData, + name: e.target.value, + }) + } + }} + maxLength={32} + /> +
+ + {communityData ? communityData.name?.length : 0} + + /{32} +
+
+
+ +
+ +
+