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

ui fixes

parent 99fbe989
No related branches found
No related tags found
1 merge request!25Feat.games ui fixes
Pipeline #36984 failed
......@@ -2,6 +2,7 @@ import { AspectRatio } from "@/components/ui/aspect-ratio";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { getGame } from "@/lib/igdb";
import { formatDate } from "@/lib/utils";
import { IGame } from "@/types/igdb-types";
import Image from "next/image";
......@@ -9,11 +10,7 @@ import Image from "next/image";
export default async function GameDetail({ params }: { params: { gameid: string } }) {
const data: IGame[] = await getGame(parseInt(params.gameid))
const date = new Date(data[0].first_release_date * 1000).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric'
})
const date = formatDate(data[0].first_release_date * 1000)
const companies = data[0].involved_companies.map((company) => {
if (company !== data[0].involved_companies[0]) {
......
import PostItem from "@/components/post-item";
import PostMessageForm from "@/components/post-messages";
import { PostMessageForm } from "@/components/post-messages";
import { Card } from "@/components/ui/card";
import { db } from "@/lib/db";
import { Prisma } from "@prisma/client";
type messageType = any // Prisma.PostUncheckedCreateInput
type messageItemProps = {
msg: messageType;
};
export default async function HomePage() {
let messages = null
......@@ -22,27 +16,27 @@ export default async function HomePage() {
Like: true
},
})
} catch (error) {
console.log("the database is not running, try: 'npx prisma migrate dev --name init' if you want to use the database")
throw new Error("the database is not running, check your .env file")
}
return (
<div>
<h1>Home WIP</h1>
<p>This will be where all Posts show up.</p>
<p>Needs a reload after posting!!</p>
// <div className="main-content px-3">
<div className="relative md:gap-10 lg:grid lg:grid-cols-[1fr_240px] px-3">
<PostMessageForm />
{messages ?
<>
{messages.map((msg) => (
<PostItem msg={msg} key={msg.id} />
))}
</>
:
<p>no messages / no database</p>}
<Card className="w-full h-full overflow-hidden p-6 md:p-12">
{messages ? messages.map((msg) => (
<PostItem msg={msg} key={msg.id} />
))
:
<p>There are no messages currently</p>}
</Card>
{/* <div className="side-content"> */}
<div className="hidden lg:block flex-col">
a
</div>
</div>
)
}
}
\ No newline at end of file
import { authOptions } from "@/lib/auth";
import { db } from "@/lib/db";
import { Prisma } from "@prisma/client";
import { getServerSession } from "next-auth/next";
import { getCurrentUser } from "@/lib/session";
import { revalidatePath } from "next/cache";
import { NextRequest, NextResponse } from "next/server";
type post = Prisma.PostUncheckedCreateInput
export async function POST(req: NextRequest) {
const session = await getServerSession(authOptions);
const user = await getCurrentUser();
if (!session) {
return NextResponse.json({ status: 401 });
if (!user) {
return NextResponse.json({ status: 401, message: 'Unauthorized' });
}
const userId = session.user.id
const data = await req.json()
console.log("router data: " + data.content, "status:")
const userId = user.id;
const content = await req.json()
console.log(content);
console.log(userId);
try {
await db.post.create({
/* data: data */
data: {
content: data.content,
content: content.gweet,
userId: userId,
published: true
}
})
console.log("created")
const path = req.nextUrl.searchParams.get('path') || '/';
revalidatePath(path);
return NextResponse.json({ status: 201, message: 'Message Created' })
} catch (error: any) {
console.log("fail" + error);
}
console.log("post")
}
export async function GET(req: NextRequest, res: NextResponse) {
try {
const data = await req.json()
console.log("router data: " + data, "status:")
} catch (error) {
}
try {
const messages = await db.post.findMany({
orderBy: {
createdAt: "desc"
}
})
return NextResponse.json({ status: 200, messages: messages })
} catch (error) {
console.log("fail" + error);
// res.status(400)
return NextResponse.json({ status: 500, message: error.message })
}
console.log("get")
}
\ No newline at end of file
import { formatDate } from "@/lib/utils";
import CommentButton from "./comment-button";
import LikeButton from "./like-button";
type messageType = any // Prisma.PostUncheckedCreateInput
type messageItemProps = {
msg: messageType;
};
export default function PostItem({ msg }: any) {
export default function PostItem({ msg }: { msg: any }) {
if (!msg.id) {
return <div></div>;
}
......@@ -20,7 +16,7 @@ export default function PostItem({ msg }: any) {
<div className="flex items-center">
<span className="font-bold mr-2">{msg.user.name}</span>
<span className="text-gray-500 text-sm">
{formatDate(new Date(msg.createdAt!))}
{formatDate(msg.createdAt)}
</span>
</div>
<div className="text-gray-800">{msg.content}</div>
......@@ -36,12 +32,4 @@ export default function PostItem({ msg }: any) {
</div>
</div>
)
};
function formatDate(date: Date) {
return date.toLocaleDateString("en-US", {
day: "numeric",
month: "short",
year: "numeric"
});
}
\ No newline at end of file
};
\ No newline at end of file
"use client"
import { Post, Prisma } from "@prisma/client";
import { useRouter } from "next/navigation";
import { startTransition, useEffect, useState } from "react";
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import * as z from "zod"
type messageType = Prisma.PostUncheckedCreateInput
import { Button } from "@/components/ui/button"
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
export default function PostMessageForm() {
import { Textarea } from "@/components/ui/textarea"
import { toast } from "@/components/ui/use-toast"
const [formData, setFormData] = useState<messageType>({ content: "" } as messageType);
const router = useRouter();
const FormSchema = z.object({
gweet: z
.string()
.min(1, { message: "Come on post something...", })
.max(1000, { message: "Gweets cannot be more that 1000 characters.", }),
})
async function postMessage(e: any) {
e.preventDefault()
console.log(formData)
const response = await fetch('http://localhost:3000/api/messages', {
export function PostMessageForm() {
const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema),
})
async function onSubmit(data: z.infer<typeof FormSchema>) {
await fetch('/api/messages', {
method: 'POST',
body: JSON.stringify(formData),
body: JSON.stringify(data),
next: { tags: ['collection'] }
})
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()
toast({
title: "Your gweet 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>
),
})
}
const characterCount = formData.content.length;
const isOverLimit = characterCount >= 1000;
const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
const { value } = e.target;
setFormData({ ...formData, content: value });
};
return (
<div>
<form onSubmit={postMessage}>
<textarea
placeholder="Write something..."
name="content"
value={formData.content}
onChange={handleInputChange}
className="w-full p-2 border border-gray-600 rounded-xl resize-none"
rows={5}
maxLength={1000}
></textarea>
<div className="flex justify-end mt-2">
<span className={`${isOverLimit ? "text-red-500" : "text-gray-500"} text-sm`}>
{characterCount}/{1000}
</span>
</div>
<button type="submit" className="mt-2 bg-gray-300 text-gray-800 px-4 py-2 rounded float-right">
Post
</button>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
<FormField
control={form.control}
name="gweet"
render={({ field }) => (
<FormItem>
<FormLabel>Gweet</FormLabel>
<FormControl>
<Textarea
placeholder="What's on your mind?"
className="resize-none"
{...field}
/>
</FormControl>
<FormDescription>
Your gweets will be public, and everyone can see them.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
</form>
</div>
</Form>
)
}
\ No newline at end of file
import * as LabelPrimitive from "@radix-ui/react-label"
import { Slot } from "@radix-ui/react-slot"
import * as React from "react"
import {
Controller,
ControllerProps,
FieldPath,
FieldValues,
FormProvider,
useFormContext,
} from "react-hook-form"
import { Label } from "@/components/ui/label"
import { cn } from "@/lib/utils"
const Form = FormProvider
type FormFieldContextValue<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
> = {
name: TName
}
const FormFieldContext = React.createContext<FormFieldContextValue>(
{} as FormFieldContextValue
)
const FormField = <
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
>({
...props
}: ControllerProps<TFieldValues, TName>) => {
return (
<FormFieldContext.Provider value={{ name: props.name }}>
<Controller {...props} />
</FormFieldContext.Provider>
)
}
const useFormField = () => {
const fieldContext = React.useContext(FormFieldContext)
const itemContext = React.useContext(FormItemContext)
const { getFieldState, formState } = useFormContext()
const fieldState = getFieldState(fieldContext.name, formState)
if (!fieldContext) {
throw new Error("useFormField should be used within <FormField>")
}
const { id } = itemContext
return {
id,
name: fieldContext.name,
formItemId: `${id}-form-item`,
formDescriptionId: `${id}-form-item-description`,
formMessageId: `${id}-form-item-message`,
...fieldState,
}
}
type FormItemContextValue = {
id: string
}
const FormItemContext = React.createContext<FormItemContextValue>(
{} as FormItemContextValue
)
const FormItem = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
const id = React.useId()
return (
<FormItemContext.Provider value={{ id }}>
<div ref={ref} className={cn("space-y-2", className)} {...props} />
</FormItemContext.Provider>
)
})
FormItem.displayName = "FormItem"
const FormLabel = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
>(({ className, ...props }, ref) => {
const { error, formItemId } = useFormField()
return (
<Label
ref={ref}
className={cn(error && "text-destructive", className)}
htmlFor={formItemId}
{...props}
/>
)
})
FormLabel.displayName = "FormLabel"
const FormControl = React.forwardRef<
React.ElementRef<typeof Slot>,
React.ComponentPropsWithoutRef<typeof Slot>
>(({ ...props }, ref) => {
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
return (
<Slot
ref={ref}
id={formItemId}
aria-describedby={
!error
? `${formDescriptionId}`
: `${formDescriptionId} ${formMessageId}`
}
aria-invalid={!!error}
{...props}
/>
)
})
FormControl.displayName = "FormControl"
const FormDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => {
const { formDescriptionId } = useFormField()
return (
<p
ref={ref}
id={formDescriptionId}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
)
})
FormDescription.displayName = "FormDescription"
const FormMessage = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, children, ...props }, ref) => {
const { error, formMessageId } = useFormField()
const body = error ? String(error?.message) : children
if (!body) {
return null
}
return (
<p
ref={ref}
id={formMessageId}
className={cn("text-sm font-medium text-destructive", className)}
{...props}
>
{body}
</p>
)
})
FormMessage.displayName = "FormMessage"
export {
useFormField,
Form,
FormItem,
FormLabel,
FormControl,
FormDescription,
FormMessage,
FormField,
}
import * as React from "react"
import { cn } from "@/lib/utils"
export interface TextareaProps
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, ...props }, ref) => {
return (
<textarea
className={cn(
"flex min-h-[80px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
)
}
)
Textarea.displayName = "Textarea"
export { Textarea }
......@@ -16,4 +16,13 @@ export function getImageURL(hashId: string, size: string): string {
// calculates the offset for the query
export function calculateOffset(page: number, limit: number): number {
return (page - 1) * limit
}
export function formatDate(data: number) {
const date = new Date(data)
return date.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric'
})
}
\ No newline at end of file
import { Comment, Like, Post, User } from "@prisma/client";
export interface IPost {
user: Post & {
user: User;
Comment: Comment[];
Like: Like[];
}
}
\ 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