Skip to content
Snippets Groups Projects
Commit d1c2af21 authored by Yusuf Akgül's avatar Yusuf Akgül :hatching_chick:
Browse files

Merge branch 'main' of gitlab.bht-berlin.de:s86116/project_ss23 into testing + some small changes

parents 5793ac18 82a1dae3
No related branches found
No related tags found
1 merge request!33Testing
Pipeline #38827 passed
Showing
with 543 additions and 410 deletions
import { NextResponse } from "next/server";
import { z } from "zod";
import { db } from "@/lib/db";
export async function GET() {
try {
const hashtags = await db.hashtag.findMany({
take: 10,
orderBy: {
score: "desc",
},
});
return NextResponse.json(hashtags, { status: 200 });
} catch (error: any) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
export async function POST(request: Request) {
const { hashtags } = await request.json();
const hashtagsSchema = z.array(z.string());
const zod = hashtagsSchema.safeParse(hashtags);
if (!zod.success) {
return NextResponse.json({ error: zod.error }, { status: 400 });
}
try {
for (const hashtag of hashtags) {
const hashtagExists = await db.hashtag.findUnique({
where: {
hashtag: hashtag.toLowerCase(),
},
});
if (hashtagExists) {
await db.hashtag.update({
where: {
hashtag: hashtag.toLowerCase(),
},
data: {
score: {
increment: 1,
},
},
});
} else {
await db.hashtag.create({
data: {
text: hashtag,
hashtag: hashtag.toLowerCase(),
},
});
}
}
return NextResponse.json(
{
message: "Hashtag(s) created",
},
{ status: 200 },
);
} catch (error: any) {
return NextResponse.json(
{
error: error.message,
},
{ status: 500 },
);
}
}
import { db } from "@/lib/db"
import { Prisma } from "@prisma/client"
type likeType = Prisma.LikeUncheckedCreateInput
/**
* Creates like if user has not liked this post.
* Deletes like if user has liked post already.
*/
export async function putLike(like: likeType): Promise<likeType | undefined> {
// check if like exists by this user and for this post
// if exists delete
// if not create
try {
const actualLike = await db.like.findFirst({
where: {
// id: like.id,
postId: like.postId,
userId: like.userId
}
})
console.log("found like: ", actualLike?.id)
if (actualLike == null) {
console.log("like is null", "postid:", like.postId, "so create it")
throw Error("Message was not liked by this user")
}
console.log("delete like", like.postId, "likeid: ", actualLike?.id)
await db.like.delete({
where: {
id: actualLike.id
}
})
/* const msg = await db.post.update({
where: {
id: like.postId
},
data: {
likeCount: { increment: -1 }
}
}) */
return undefined;
} catch {
const createdLike = await db.like.create({
data: {
postId: like.postId,
userId: like.userId
}
})
const updatedMessage = await db.post.update({
where: {
id: like.postId
},
data: {
likeCount: { increment: 1 }
}
})
}
}
export async function putLikeComment(like: likeType) {
// check if like exists by this user and for this post
// if exists delete
// if not create
try {
const actualLike = await db.like.findFirst({
where: {
// id: like.id,
postId: like.postId,
commentId: like.commentId,
userId: like.userId
}
})
console.log("found like: ", actualLike?.id)
if (actualLike == null) {
console.log("like is null", like.commentId, "so create it")
const createdLike = await db.like.create({
data: {
postId: like.postId,
userId: like.userId,
commentId: like.commentId
}
})
} else {
console.log("delete like", like.commentId, "postid:", like.postId, "likeid: ", actualLike?.id)
await db.like.delete({
where: {
id: actualLike.id
}
})
}
/* const msg = await db.comment.update({
where: {
id: like.postId
},
data: {
likeCount: { increment: -1 }
}
}) */
} catch {
/* const updatedMessage = await db.comment.update({
where: {
id: like.postId
},
data: {
likeCount: { increment: 1 }
}
}) */
}
}
\ No newline at end of file
import { Prisma } from "@prisma/client";
import { NextRequest, NextResponse } from "next/server";
import { putLike, putLikeComment } from "./likeService";
import { getServerSession } from "next-auth/next";
import { authOptions } from "@/lib/auth";
import { revalidatePath } from "next/cache";
type like = Prisma.LikeUncheckedCreateInput
export async function PUT(req: NextRequest) {
const session = await getServerSession(authOptions);
if (!session) {
return NextResponse.json({ status: 401 });
}
const userId = session.user.id
const data: like = await req.json()
data.userId = userId;
console.log("router data: " + data, "status:")
try {
if (data.commentId == undefined) {
const msg = await putLike(data)
} else {
putLikeComment(data)
}
const path = req.nextUrl.searchParams.get('path') || '/';
revalidatePath(path);
return NextResponse.json({ status: 200, message: 'Like handled' })
} catch (error) {
console.log("fail" + error);
return NextResponse.json(error, { status: 500 });
}
}
\ No newline at end of file
import { db } from "@/lib/db";
import { getCurrentUser } from "@/lib/session";
import { revalidatePath } from "next/cache";
import { NextRequest, NextResponse } from "next/server";
export async function POST(req: NextRequest) {
const user = await getCurrentUser();
if (!user) {
return NextResponse.json({ status: 401, message: 'Unauthorized' });
}
const userId = user.id;
const content = await req.json()
try {
await db.post.create({
data: {
content: content.gweet,
userId: userId,
}
})
const path = req.nextUrl.searchParams.get('path') || '/';
revalidatePath(path);
return NextResponse.json({ status: 201, message: 'Message Created' })
} catch (error: any) {
return NextResponse.json({ status: 500, message: error.message })
}
}
export async function GET() {
try {
const messages = await db.post.findMany({
orderBy: {
createdAt: "desc"
},
include: {
user: true,
Comment: true,
Like: true
},
})
return NextResponse.json(messages);
} catch (error) {
return NextResponse.json(error, { status: 500 });
}
}
\ No newline at end of file
import { getCurrentUser } from "@/lib/session";
import { createUploadthing, type FileRouter } from "uploadthing/next";
const f = createUploadthing();
export const ourFileRouter = {
imageUploader: f({ image: { maxFileSize: "4MB", maxFileCount: 4 } })
.middleware(async ({ req }) => {
const user = await getCurrentUser();
if (!user) throw new Error("Unauthorized");
return { userId: user.id };
})
.onUploadComplete(async ({ metadata, file }) => { }),
} satisfies FileRouter;
export type OurFileRouter = typeof ourFileRouter;
\ No newline at end of file
import { createNextRouteHandler } from "uploadthing/next";
import { ourFileRouter } from "./core";
export const { GET, POST } = createNextRouteHandler({
router: ourFileRouter,
});
\ No newline at end of file
File moved
import { Inter } from 'next/font/google'
import './globals.css'
import Providers from '@/components/react-query/provider'
import { ThemeProvider } from '@/components/ui/theme-provider'
import { Toaster } from '@/components/ui/toaster'
import Providers from '@/lib/react-query/provider'
const inter = Inter({ subsets: ['latin'] })
......
{
"style": "default",
"rsc": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "app/globals.css",
"baseColor": "slate",
"cssVariables": true
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
}
}
\ No newline at end of file
"use client"
import { useState } from "react";
import { Card } from "./ui/card";
import GameItem from "./game-item";
import { IGame } from "@/types/igdb-types";
import { User } from "@prisma/client";
import AddGameToPlanList from "./add-game-to-plan-list";
import AddGameToPlayingList from "./add-game-to-playing-list";
import AddGameToFinishedList from "./add-game-to-finished-list";
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "./ui/select";
export default function AddGameDropdown(props: { gameid: string, fullUser: User }) {
return (
<>
<Select>
<SelectTrigger className={`bg-background border-full w-32 h-8}`}>
<SelectValue placeholder="Status" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Status</SelectLabel>
<AddGameToPlanList user={props.fullUser!} gameId={props.gameid} />
<AddGameToFinishedList user={props.fullUser!} gameId={props.gameid} />
<AddGameToPlayingList user={props.fullUser!} gameId={props.gameid} />
</SelectGroup>
</SelectContent>
</Select>
</>
)
}
"use client"
import { User } from "@prisma/client";
import { useRouter } from "next/navigation";
import { startTransition } from "react";
import { Button } from "./ui/button";
export default function AddGameToFinishedList(props: { gameId: string, user: User }) {
const router = useRouter();
const gameId = parseFloat(props.gameId);
const user = props.user;
let formData: {
id: String;
gameId: Number;
add: boolean;
planningGameList: number[] | undefined;
playingGameList: number[] | undefined;
finishedGameList: number[] | undefined;
} = {
id: "",
gameId: -1,
add: true,
planningGameList: undefined,
playingGameList: undefined,
finishedGameList: undefined
};
async function removeGame(e: any) {
e.preventDefault()
formData.id = user.id;
formData.finishedGameList = props.user.finishedGameList.filter((id) => id !== gameId)
console.log(formData.finishedGameList)
const response = await fetch('/api/gamelists', {
method: 'PUT',
body: JSON.stringify(formData)
})
startTransition(() => {
// Refresh the current route and fetch new data from the server without
// losing client-side browser or React state.
router.refresh();
});
return await response.json()
}
async function addGame(e: any) {
e.preventDefault()
formData.id = user.id;
props.user.finishedGameList.push(gameId)
formData.finishedGameList = props.user.finishedGameList;
const response = await fetch('/api/gamelists', {
method: 'PUT',
body: JSON.stringify(formData)
})
startTransition(() => {
// Refresh the current route and fetch new data from the server without
// losing client-side browser or React state.
router.refresh();
});
return await response.json()
}
let button = <div></div>;
try {
if (!props.user.finishedGameList.includes(parseFloat(props.gameId))) {
button = (
<form onSubmit={addGame}>
<Button type="submit" size="lg">
Add Game To finished-playing-List
</Button>
</form>
)
} else {
button = (
<form onSubmit={removeGame}>
<Button type="submit" size="lg" variant={"secondary"}>
Remove Game From finished-playing-List
</Button>
</form>
)
}
} catch (error) {
// throw new Error("Failed to check finished-playing-List");
}
return (
button
)
}
"use client"
import { User } from "@prisma/client";
import { useRouter } from "next/navigation";
import { startTransition } from "react";
import { Button } from "./ui/button";
export default function AddGameToPlanList(props: { gameId: string, user: User }) {
const router = useRouter();
const gameId = parseFloat(props.gameId);
const user = props.user;
let formData: {
id: String;
gameId: Number;
add: boolean;
planningGameList: number[] | undefined;
playingGameList: number[] | undefined;
finishedGameList: number[] | undefined;
} = {
id: "",
gameId: -1,
add: true,
planningGameList: undefined,
playingGameList: undefined,
finishedGameList: undefined
};
async function removeGame(e: any) {
e.preventDefault()
formData.id = user.id;
formData.planningGameList = props.user.planningGameList.filter((id) => id !== gameId)
console.log(formData.planningGameList)
const response = await fetch('/api/gamelists', {
method: 'PUT',
body: JSON.stringify(formData)
})
startTransition(() => {
// Refresh the current route and fetch new data from the server without
// losing client-side browser or React state.
router.refresh();
});
return await response.json()
}
async function addGame(e: any) {
e.preventDefault()
formData.id = user.id;
props.user.planningGameList.push(gameId)
formData.planningGameList = props.user.planningGameList;
const response = await fetch('/api/gamelists', {
method: 'PUT',
body: JSON.stringify(formData)
})
startTransition(() => {
// Refresh the current route and fetch new data from the server without
// losing client-side browser or React state.
router.refresh();
});
return await response.json()
}
let button = <div></div>;
try {
if (!props.user.planningGameList.includes(parseFloat(props.gameId))) {
button = (
<form onSubmit={addGame}>
<Button type="submit" size="lg">
Add Game To Planning-to-play-List
</Button>
</form>
)
} else {
button = (
<form onSubmit={removeGame}>
<Button type="submit" size="lg" variant={"secondary"}>
Remove Game From Planning-to-play-List
</Button>
</form>
)
}
} catch (error) {
// throw new Error("Failed to check Planning-to-play-List");
}
return (
button
)
}
"use client"
import { User } from "@prisma/client";
import { useRouter } from "next/navigation";
import { startTransition } from "react";
import { Button } from "./ui/button";
export default function AddGameToPlayingList(props: { gameId: string, user: User }) {
const router = useRouter();
const gameId = parseFloat(props.gameId);
const user = props.user;
let formData: {
id: String;
gameId: Number;
add: boolean;
planningGameList: number[] | undefined;
playingGameList: number[] | undefined;
finishedGameList: number[] | undefined;
} = {
id: "",
gameId: -1,
add: true,
planningGameList: undefined,
playingGameList: undefined,
finishedGameList: undefined
};
async function removeGame(e: any) {
e.preventDefault()
formData.id = user.id;
formData.playingGameList = props.user.playingGameList.filter((id) => id !== gameId)
console.log(formData.playingGameList)
const response = await fetch('/api/gamelists', {
method: 'PUT',
body: JSON.stringify(formData)
})
startTransition(() => {
// Refresh the current route and fetch new data from the server without
// losing client-side browser or React state.
router.refresh();
});
return await response.json()
}
async function addGame(e: any) {
e.preventDefault()
formData.id = user.id;
props.user.playingGameList.push(gameId)
formData.playingGameList = props.user.playingGameList;
const response = await fetch('/api/gamelists', {
method: 'PUT',
body: JSON.stringify(formData)
})
console.log("add game")
startTransition(() => {
// Refresh the current route and fetch new data from the server without
// losing client-side browser or React state.
router.refresh();
});
return await response.json()
}
let button = <div></div>;
try {
if (!props.user.playingGameList.includes(parseFloat(props.gameId))) {
button = (
<form onSubmit={addGame}>
<Button type="submit" size="lg">
Add Game To currently-playing-List
</Button>
</form>
)
} else {
button = (
<form onSubmit={removeGame}>
<Button type="submit" size="lg" variant={"secondary"}>
Remove Game From currently-playing-List
</Button>
</form>
)
}
} catch (error) {
// throw new Error("Failed to check playing-to-play-List");
}
return (
button
)
}
......@@ -4,7 +4,7 @@ import { useRouter } from "next/navigation";
import { startTransition } from "react";
import { Button } from "./ui/button";
export default function AddGameToList(props: { userGameList: Number[], gameId: string }) {
export default function AddGameToFavList(props: { userGameList: Number[], gameId: string }) {
const router = useRouter();
const gameId = props.gameId
......@@ -15,7 +15,7 @@ export default function AddGameToList(props: { userGameList: Number[], gameId: s
formData.gameId = gameId;
formData.add = false;
const response = await fetch('/api/favgameslist', {
const response = await fetch('/api/users/favgameslist', {
method: 'PUT',
body: JSON.stringify(formData)
})
......@@ -33,7 +33,7 @@ export default function AddGameToList(props: { userGameList: Number[], gameId: s
formData.gameId = gameId;
formData.add = true;
const response = await fetch('/api/favgameslist', {
const response = await fetch('/api/users/favgameslist', {
method: 'PUT',
body: JSON.stringify(formData)
})
......@@ -53,7 +53,7 @@ export default function AddGameToList(props: { userGameList: Number[], gameId: s
button = (
<form onSubmit={addGame}>
<Button type="submit" size="lg">
Add Game To List
Add Game To Favorite List
</Button>
</form>
)
......@@ -61,13 +61,13 @@ export default function AddGameToList(props: { userGameList: Number[], gameId: s
button = (
<form onSubmit={removeGame}>
<Button type="submit" size="lg" variant={"secondary"}>
Remove Game From List
Remove Game From Favorite List
</Button>
</form>
)
}
} catch (error) {
throw new Error("Failed to fetch comments");
// throw new Error("Failed to check list");
}
return (
......
"use client";
import { useRouter } from "next/navigation";
import { Icons } from "./icons";
import { Button } from "./ui/button";
export const BackButton = () => {
const router = useRouter();
return (
<Button
variant="ghost"
size="icon"
onClick={() => router.back()}
title="Go Back"
>
<Icons.chevronLeft />
</Button>
);
};
\ No newline at end of file
import { BackButton } from "@/components/back-button";
export const BackHeader = ({ children }: { children: React.ReactNode }) => {
return (
<div className="flex items-center space-x-3">
<BackButton />
{children}
</div>
);
}
\ No newline at end of file
// "use client"
// import { zodResolver } from "@hookform/resolvers/zod";
// import { useForm } from "react-hook-form";
// import * as z from "zod";
// import { Button } from "@/components/ui/button";
// import {
// Form,
// FormControl,
// FormDescription,
// FormField,
// FormItem,
// FormLabel,
// FormMessage,
// } from "@/components/ui/form";
// import { Textarea } from "@/components/ui/textarea";
// import { toast } from "@/components/ui/use-toast";
// import { FormEvent, Fragment, useEffect, useState } from "react";
// import CommentItem from "./comment-item";
// import { Icons } from "./icons";
// import { Card } from "./ui/card";
// import { Separator } from "./ui/separator";
// import { Skeleton } from "./ui/skeleton";
// const FormSchema = z.object({
// gweet: z
// .string()
// .min(1, { message: "Come on post something...", })
// .max(1000, { message: "Gweets cannot be more that 1000 characters.", }),
// })
// export function PostCommentForm(props: { postid: string }) {
// const [isGweetLoading, setIsGweetLoading] = useState<boolean>(false);
// const [isLoading, setIsLoading] = useState<boolean>(false);
// const [messages, setMessages] = useState<any[]>([]);
// const form = useForm<z.infer<typeof FormSchema>>({
// resolver: zodResolver(FormSchema),
// })
// async function onCommentGweet(data: z.infer<typeof FormSchema>) {
// setIsGweetLoading(true);
// await fetch('/api/comments', {
// method: 'POST',
// body: JSON.stringify(props.postid)
// })
// toast({
// title: "Your comment is being processed...",
// description: (
// <pre className="mt-2 w-[340px] rounded-md bg-slate-600 p-4">
// <code className="text-white">{JSON.stringify(data, null, 2)}</code>
// </pre>
// ),
// })
// setIsGweetLoading(false);
// form.setValue('gweet', '');
// await fetchMessages();
// }
// async function fetchMessages() {
// setIsLoading(true);
// try {
// const res = await fetch(`/api/comments?postid=${props.postid}`);
// if (!res.ok) {
// throw new Error("Failed to fetch comments");
// }
// const data = await res.json();
// setMessages(data);
// } catch (error) {
// return toast({
// variant: "destructive",
// title: "Uh oh! Something went wrong.",
// description: "Failed to fetch messages. Please try again.",
// });
// }
// setIsLoading(false);
// }
// useEffect(() => {
// fetchMessages();
// }, []);
// async function onSubmit(event: FormEvent<HTMLFormElement>) {
// event.preventDefault();
// await fetchMessages();
// }
// // console.log((messages[0] as IPost).user.image);
// return (
// <div>
// {/* <PostItem msg={(messages[0])} /> */}
// <Form {...form}>
// <form onSubmit={form.handleSubmit(onCommentGweet)} className="space-y-6">
// <FormField
// control={form.control}
// name="gweet"
// render={({ field }) => (
// <FormItem>
// <FormLabel>Comment</FormLabel>
// <FormControl>
// <Textarea
// placeholder="What's on your mind?"
// className="resize-none"
// disabled={isGweetLoading}
// {...field}
// />
// </FormControl>
// <FormDescription>
// Your comment will be public, and everyone can see them.
// </FormDescription>
// <FormMessage />
// </FormItem>
// )}
// />
// <Button type="submit" disabled={isGweetLoading}>Submit</Button>
// </form>
// </Form>
// <Card className="w-full h-full overflow-hidden p-6 md:p-12 mt-12">
// <form onSubmit={onSubmit}>
// <Button disabled={isLoading} type="submit" className="w-full mb-6">
// {isLoading && (
// <Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
// )}
// Load More
// </Button>
// {messages.length > 0 ? (
// messages.map((message: any) => (
// <Fragment key={message.id}>
// <CommentItem msg={message} />
// <Separator className="mt-3 mb-6" />
// </Fragment>
// ))
// ) : (
// <>
// {Array.from({ length: 4 }, (_, i) => i + 1).map((i) => (
// <>
// <div className="flex">
// <Skeleton className="h-10 w-10 rounded-full" />
// <div className="ml-4 flex flex-col flex-grow">
// <div>
// <div className="flex items-center">
// <div className="mx-auto w-full space-y-6">
// <Skeleton className="h-[30px] w-1/4" />
// <Skeleton className="h-[20px] w-2/3" />
// <Skeleton className="h-[20px] w-full" />
// </div>
// </div>
// </div>
// </div>
// </div>
// <Separator className="mt-3 mb-6" />
// </>
// ))}
// </>
// )}
// </form>
// </Card>
// </div>
// )
// }
\ No newline at end of file
// import { formatTimeElapsed } from "@/lib/utils";
// import { UserAvatar } from "./user-avatar";
// export default function CommentItem({ msg }: { msg: any }) {
// return (
// <div className="flex">
// <UserAvatar
// user={{ name: msg.user.username || null, image: msg.user.image || null }}
// className="h-10 w-10"
// />
// <div className="ml-4 flex flex-col flex-grow">
// <div>
// <div className="flex items-center">
// <h1 className="font-bold mr-2">{msg.user.name}</h1>
// <h1 className="text-sky-500 text-sm">
// @{msg.user.username}
// </h1>
// <h1 className="text-gray-500 text-sm ml-auto">
// {formatTimeElapsed(msg.createdAt)}
// </h1>
// </div>
// <h1>{msg.message}</h1>
// </div>
// </div>
// </div>
// )
// }
\ No newline at end of file
import { postHashtags, retrieveHashtagsFromGweet } from "@/components/trends";
import { uploadFiles } from "@/lib/uploadthing";
export const postGweet = async ({
content,
files,
authorId,
replyToGweetId,
quoteGweetId,
}: {
content: string;
files: File[];
authorId: string;
replyToGweetId?: string | null;
quoteGweetId?: string | null;
}) => {
const gweet = {
content,
authorId,
...(replyToGweetId && { replyToGweetId }),
...(quoteGweetId && { quoteGweetId }),
};
try {
let fileprops: { fileUrl: string; fileKey: string; }[] = [];
if (files.length > 0) {
fileprops = await uploadFiles({ files, endpoint: 'imageUploader' })
}
const data = await fetch('/api/gweets', {
method: 'POST',
body: JSON.stringify({ gweet, fileprops })
}).then((result) => result.json())
const hashtags = retrieveHashtagsFromGweet(content);
if (hashtags) await postHashtags(hashtags);
return data;
} catch (error: any) {
return error.response.data;
}
};
\ No newline at end of file
"use client";
import { useState } from "react";
import { CreateGweet } from "./create-gweet";
export const CreateGweetWrapper = ({
replyToGweetId,
}: {
replyToGweetId: string | null;
}) => {
const [isComment, setIsComment] = useState(true);
return (
<div className="px-6">
<CreateGweet
replyToGweetId={replyToGweetId}
placeholder="Gweet your reply..."
isComment={isComment}
/>
{isComment && (
<button
onClick={() => {
setIsComment(false);
}}
/>
)}
</div>
);
};
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment