-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
29 changed files
with
4,454 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
"use client"; | ||
|
||
import { useParams } from "next/navigation"; | ||
import { graphql, useFragment, useMutation } from "react-relay"; | ||
import { z } from "zod"; | ||
|
||
import { | ||
Button, | ||
Form, | ||
FormControl, | ||
FormField, | ||
FormItem, | ||
FormLabel, | ||
FormMessage, | ||
Textarea, | ||
useForm, | ||
} from "@kampus/ui"; | ||
|
||
import { CreatePostCommentForm_viewer$key } from "./__generated__/CreatePostCommentForm_viewer.graphql"; | ||
|
||
const mutation = graphql` | ||
mutation CreatePostCommentFormMutation( | ||
$content: String! | ||
$postID: String! | ||
$connections: [ID!]! | ||
) { | ||
createPanoComment(input: { content: $content, postID: $postID }) { | ||
edge @prependEdge(connections: $connections) { | ||
cursor | ||
node { | ||
id | ||
content | ||
createdAt | ||
owner { | ||
displayName | ||
} | ||
} | ||
} | ||
error { | ||
... on UserError { | ||
message | ||
} | ||
} | ||
} | ||
} | ||
`; | ||
|
||
const viewerFragment = graphql` | ||
fragment CreatePostCommentForm_viewer on Viewer { | ||
actor { | ||
displayName | ||
} | ||
} | ||
`; | ||
|
||
const formSchema = z.object({ | ||
content: z.string().min(1, { message: "Yorum kısmı boş bırakılamaz." }), | ||
}); | ||
|
||
type FormSchema = z.infer<typeof formSchema>; | ||
|
||
interface Props { | ||
viewer: CreatePostCommentForm_viewer$key; | ||
connectionID?: string; | ||
onCompleted?: () => void; | ||
} | ||
|
||
export function CreatePanoCommentForm(props: Props) { | ||
const [commit, isInFlight] = useMutation(mutation); | ||
const { id: postID } = useParams(); | ||
const { actor } = useFragment(viewerFragment, props.viewer); | ||
|
||
const form = useForm(formSchema, { | ||
defaultValues: { | ||
content: "", | ||
}, | ||
}); | ||
|
||
const onSubmit = (values: FormSchema) => { | ||
commit({ | ||
variables: { | ||
content: values.content, | ||
postID: decodeURIComponent(postID!), | ||
connections: [props.connectionID].filter(Boolean), | ||
}, | ||
onError: (error) => { | ||
console.error(error); | ||
}, | ||
onCompleted: () => { | ||
props.onCompleted?.(); | ||
}, | ||
}); | ||
}; | ||
|
||
return ( | ||
<Form {...form}> | ||
{/* eslint-disable-next-line @typescript-eslint/no-misused-promises */} | ||
<form className="flex flex-col gap-2" onSubmit={form.handleSubmit(onSubmit)}> | ||
<FormField | ||
control={form.control} | ||
name="content" | ||
render={(props) => ( | ||
<FormItem> | ||
<FormLabel>Senin yorumun</FormLabel> | ||
<FormControl> | ||
<Textarea | ||
placeholder={ | ||
actor ? "Yorumunu buraya ekle..." : "Yorum yapmak için giriş yapmalısın." | ||
} | ||
className="max-h-64 resize-y" | ||
disabled={!actor} | ||
{...props.field} | ||
/> | ||
</FormControl> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
<div className="flex"> | ||
<Button type="submit" disabled={isInFlight || !actor}> | ||
Gönder | ||
</Button> | ||
</div> | ||
</form> | ||
</Form> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
"use client"; | ||
|
||
import { graphql, usePreloadedQuery } from "react-relay"; | ||
|
||
import { type SerializablePreloadedQuery } from "@kampus/relay"; | ||
import useSerializablePreloadedQuery from "@kampus/relay/use-serializable-preloaded-query"; | ||
|
||
import { SinglePostContainerQuery } from "./__generated__/SinglePostContainerQuery.graphql"; | ||
import { SinglePostFeed } from "./SinglePostFeed"; | ||
|
||
interface Props { | ||
preloadedQuery: SerializablePreloadedQuery<SinglePostContainerQuery>; | ||
} | ||
|
||
const query = graphql` | ||
query SinglePostContainerQuery($id: ID!) { | ||
viewer { | ||
...SinglePostFeed_viewer | ||
} | ||
pano { | ||
post(id: $id) { | ||
...SinglePostFeed_post | ||
...SinglePostFeed_comments | ||
} | ||
} | ||
} | ||
`; | ||
|
||
export const SinglePostContainer = (props: Props) => { | ||
const queryRef = useSerializablePreloadedQuery(props.preloadedQuery); | ||
const data = usePreloadedQuery(query, queryRef); | ||
|
||
if (!data.pano.post) { | ||
return null; | ||
} | ||
|
||
if (!data.viewer) { | ||
return null; | ||
} | ||
|
||
console.log(data); | ||
|
||
return ( | ||
<div> | ||
<SinglePostFeed post={data.pano.post} viewer={data.viewer} comments={data.pano.post} /> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { graphql, useFragment, usePaginationFragment } from "react-relay"; | ||
|
||
import { Separator } from "@kampus/ui"; | ||
|
||
import { SinglePostFeed_comments$key } from "./__generated__/SinglePostFeed_comments.graphql"; | ||
import { SinglePostFeed_post$key } from "./__generated__/SinglePostFeed_post.graphql"; | ||
import { SinglePostFeed_viewer$key } from "./__generated__/SinglePostFeed_viewer.graphql"; | ||
import { CreatePanoCommentForm } from "./CreatePostCommentForm"; | ||
import { CommentItem } from "./features/comment-list/CommentItem"; | ||
import { PostItem } from "./features/post-list/PostItem"; | ||
|
||
interface SinglePostFeedProps { | ||
post: SinglePostFeed_post$key; | ||
viewer: SinglePostFeed_viewer$key; | ||
comments: SinglePostFeed_comments$key; | ||
} | ||
|
||
const fragment = graphql` | ||
fragment SinglePostFeed_comments on PanoPost | ||
@argumentDefinitions( | ||
after: { type: "String" } | ||
first: { type: "Int", defaultValue: 10 } | ||
before: { type: "String" } | ||
last: { type: "Int" } | ||
) | ||
@refetchable(queryName: "SinglePostFeedPaginationQuery") { | ||
comments(first: $first, after: $after, last: $last, before: $before) | ||
@connection(key: "SinglePostFeedFragment__comments") { | ||
__id | ||
edges { | ||
node { | ||
id | ||
content | ||
createdAt | ||
owner { | ||
displayName | ||
} | ||
...CommentItem_comment | ||
} | ||
} | ||
} | ||
} | ||
`; | ||
|
||
const postFragment = graphql` | ||
fragment SinglePostFeed_post on PanoPost { | ||
...PostItem_post | ||
} | ||
`; | ||
|
||
const viewerFragment = graphql` | ||
fragment SinglePostFeed_viewer on Viewer { | ||
...PostItem_viewer | ||
...CommentItem_viewer | ||
...CreatePostCommentForm_viewer | ||
} | ||
`; | ||
|
||
export const SinglePostFeed = (props: SinglePostFeedProps) => { | ||
const post = useFragment(postFragment, props.post); | ||
const viewer = useFragment(viewerFragment, props.viewer); | ||
const { data } = usePaginationFragment(fragment, props.comments); | ||
|
||
const comments = data.comments; | ||
|
||
return ( | ||
<div className="flex flex-col gap-4"> | ||
<PostItem post={post} showContent viewerRef={viewer} /> | ||
<Separator /> | ||
<CreatePanoCommentForm viewer={viewer} connectionID={comments?.__id} /> | ||
<h2>Yorumlar</h2> | ||
{comments?.edges?.map((edge) => { | ||
if (!edge?.node) return null; | ||
return ( | ||
<CommentItem | ||
key={edge.node.id} | ||
comment={edge.node} | ||
viewerRef={viewer} | ||
connectionID={comments.__id} | ||
/> | ||
); | ||
})} | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
"use client"; | ||
|
||
import React from "react"; | ||
import { Check, X } from "lucide-react"; | ||
import { graphql, useFragment, useMutation } from "react-relay"; | ||
import { z } from "zod"; | ||
|
||
import { | ||
Button, | ||
Form, | ||
FormControl, | ||
FormField, | ||
FormItem, | ||
FormMessage, | ||
Textarea, | ||
useForm, | ||
} from "@kampus/ui"; | ||
|
||
import { UpdateCommentForm_viewer$key } from "./__generated__/UpdateCommentForm_viewer.graphql"; | ||
|
||
const mutation = graphql` | ||
mutation UpdateCommentFormMutation($content: String!, $id: ID!) { | ||
updatePanoComment(input: { content: $content, id: $id }) { | ||
edge { | ||
cursor | ||
node { | ||
id | ||
content | ||
createdAt | ||
owner { | ||
displayName | ||
} | ||
} | ||
} | ||
error { | ||
... on UserError { | ||
message | ||
} | ||
} | ||
} | ||
} | ||
`; | ||
|
||
const viewerFragment = graphql` | ||
fragment UpdateCommentForm_viewer on Viewer { | ||
actor { | ||
displayName | ||
} | ||
} | ||
`; | ||
|
||
const formSchema = z.object({ | ||
content: z.string().min(1, { message: "Yorum kısmı boş bırakılamaz." }), | ||
}); | ||
|
||
type FormSchema = z.infer<typeof formSchema>; | ||
|
||
interface Props { | ||
viewer: UpdateCommentForm_viewer$key; | ||
connectionID?: string; | ||
onCompleted?: () => void; | ||
defaultValue: string; | ||
setEditing: React.Dispatch<React.SetStateAction<boolean>>; | ||
commentID: string; | ||
} | ||
|
||
export function UpdateCommentForm(props: Props) { | ||
const [commit, isInFlight] = useMutation(mutation); | ||
const { actor } = useFragment(viewerFragment, props.viewer); | ||
|
||
const form = useForm(formSchema, { | ||
defaultValues: { | ||
content: props.defaultValue, | ||
}, | ||
}); | ||
|
||
const onSubmit = (values: FormSchema) => { | ||
commit({ | ||
variables: { | ||
content: values.content, | ||
id: props.commentID, | ||
connections: [props.connectionID].filter(Boolean), | ||
}, | ||
onError: (error) => { | ||
console.error(error); | ||
}, | ||
onCompleted: () => { | ||
props.onCompleted?.(); | ||
props.setEditing(false); | ||
}, | ||
}); | ||
}; | ||
|
||
return ( | ||
<Form {...form}> | ||
{/* eslint-disable-next-line @typescript-eslint/no-misused-promises */} | ||
<form className="flex flex-col gap-2" onSubmit={form.handleSubmit(onSubmit)}> | ||
<FormField | ||
control={form.control} | ||
name="content" | ||
render={(props) => ( | ||
<FormItem> | ||
<FormControl> | ||
<Textarea | ||
placeholder={ | ||
actor ? "Yorumunu buraya ekle..." : "Yorum yapmak için giriş yapmalısın." | ||
} | ||
className="max-h-64 resize-y" | ||
disabled={!actor} | ||
{...props.field} | ||
/> | ||
</FormControl> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
<div className="flex gap-2"> | ||
<Button | ||
size="icon" | ||
variant="destructive" | ||
disabled={isInFlight} | ||
onClick={() => props.setEditing(false)} | ||
> | ||
<X size={16} /> | ||
</Button> | ||
<Button disabled={isInFlight} size="icon" type="submit"> | ||
<Check size={16} /> | ||
</Button> | ||
</div> | ||
</form> | ||
</Form> | ||
); | ||
} |
Oops, something went wrong.