Skip to content

Commit

Permalink
Merge pull request #254 from JAJAKUnit16/comment_on_posts
Browse files Browse the repository at this point in the history
Comment on posts
  • Loading branch information
lemredd committed Oct 22, 2022
2 parents 47c6774 + 179715f commit a5985b9
Show file tree
Hide file tree
Showing 49 changed files with 1,597 additions and 190 deletions.
8 changes: 6 additions & 2 deletions common_front-end/fetchers/comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import type {
CommentDocument,
CommentListDocument,
DeserializedCommentDocument,
DeserializedCommentListDocument
DeserializedCommentListDocument,
CommentRelationships
} from "$/types/documents/comment"

import { COMMENT_LINK } from "$/constants/template_links"
Expand All @@ -22,7 +23,10 @@ export default class CommentFetcher extends BaseFetcher<
CommentDocument,
CommentListDocument,
DeserializedCommentDocument,
DeserializedCommentListDocument
DeserializedCommentListDocument,
{
"extraCreateData": CommentRelationships<"create">
}
> {
constructor() {
super(COMMENT_LINK)
Expand Down
159 changes: 159 additions & 0 deletions components/comment/create_field.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import flushPromises from "flush-promises"
import { shallowMount } from "@vue/test-utils"

import { COMMENT_LINK } from "$/constants/template_links"

import RequestEnvironment from "$/singletons/request_environment"

import Component from "./create_field.vue"

describe("Component: comment/create_field", () => {
it("may submit independently", async() => {
const postID = "1"
const userID = "2"
const content = "Hello world"
const commentIdentifier = {
"id": "1",
"type": "comment"
}
const comment = {
"data": {
"attributes": { content },
...commentIdentifier
}
}
const userProfile = {
"data": {
"id": userID,
"type": "user"
}
}
const post = {
"id": postID,
"type": "post"
}
fetchMock.mockResponseOnce(
JSON.stringify(comment),
{ "status": RequestEnvironment.status.OK }
)
const wrapper = shallowMount<any>(Component, {
"global": {
"provide": {
"pageContext": {
"pageProps": {
userProfile
}
}
}
},
"props": {
post
}
})

const field = wrapper.findComponent({ "name": "TextualField" })
await field.setValue(content)
await field.vm.$emit("saveImplicitly")
await flushPromises()

const castFetch = fetch as jest.Mock<any, any>
const [ [ firstRequest ] ] = castFetch.mock.calls
expect(firstRequest).toHaveProperty("method", "POST")
expect(firstRequest).toHaveProperty("url", COMMENT_LINK.unbound)
const firstRequestBody = await firstRequest.json()
expect(firstRequestBody).toHaveProperty("data.type", "comment")
expect(firstRequestBody).toHaveProperty("data.attributes.content", content)
expect(firstRequestBody).not.toHaveProperty("data.relationships.parentComment")
expect(firstRequestBody).toHaveProperty("data.relationships.user.data.id", userID)
expect(firstRequestBody).toHaveProperty("data.relationships.post.data.id", postID)

const updates = wrapper.emitted("createComment")
expect(updates).toHaveLength(1)
expect(updates).toHaveProperty("0.0.type", "comment")
expect(updates).toHaveProperty("0.0.content", content)
expect(updates).toHaveProperty("0.0.id", commentIdentifier.id)
expect(updates).toHaveProperty("0.0.user", userProfile)
// eslint-disable-next-line no-undefined
expect(updates).toHaveProperty("0.0.parentComment", undefined)
expect(updates).toHaveProperty("0.0.post.data", post)
})

it("may submit dependently", async() => {
const postID = "1"
const userID = "2"
const parentCommentID = "3"
const content = "Hello world"
const commentIdentifier = {
"id": "1",
"type": "comment"
}
const comment = {
"data": {
"attributes": { content },
...commentIdentifier
}
}
const userProfile = {
"data": {
"id": userID,
"type": "user"
}
}
const parentComment = {
"id": parentCommentID,
"type": "comment"
}
const post = {
"id": postID,
"type": "post"
}

fetchMock.mockResponseOnce(
JSON.stringify(comment),
{ "status": RequestEnvironment.status.OK }
)
const wrapper = shallowMount<any>(Component, {
"global": {
"provide": {
"pageContext": {
"pageProps": {
userProfile
}
}
}
},
"props": {
parentComment,
post
}
})

const field = wrapper.findComponent({ "name": "TextualField" })
await field.setValue(content)
await field.vm.$emit("saveImplicitly")
await flushPromises()

const castFetch = fetch as jest.Mock<any, any>
const [ [ firstRequest ] ] = castFetch.mock.calls
expect(firstRequest).toHaveProperty("method", "POST")
expect(firstRequest).toHaveProperty("url", COMMENT_LINK.unbound)
const firstRequestBody = await firstRequest.json()
expect(firstRequestBody).toHaveProperty("data.type", "comment")
expect(firstRequestBody).toHaveProperty("data.attributes.content", content)
expect(firstRequestBody).toHaveProperty("data.relationships.user.data.id", userID)
expect(firstRequestBody).toHaveProperty("data.relationships.post.data.id", postID)
expect(firstRequestBody).toHaveProperty(
"data.relationships.parentComment.data.id",
parentCommentID
)

const updates = wrapper.emitted("createComment")
expect(updates).toHaveLength(1)
expect(updates).toHaveProperty("0.0.type", "comment")
expect(updates).toHaveProperty("0.0.content", content)
expect(updates).toHaveProperty("0.0.id", commentIdentifier.id)
expect(updates).toHaveProperty("0.0.user", userProfile)
expect(updates).toHaveProperty("0.0.parentComment.data", parentComment)
expect(updates).toHaveProperty("0.0.post.data", post)
})
})
104 changes: 104 additions & 0 deletions components/comment/create_field.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<template>
<div>
<TextualField
v-model="content"
type="text"
:may-save-implicitly="true"
@save-implicitly="submit"/>
<button class="send-btn material-icons" @click="submit">
send
</button>
</div>
</template>

<style lang="scss">
</style>

<script setup lang="ts">
import { ref, computed, inject } from "vue"
import type { PageContext } from "$/types/renderer"
import type { DeserializedUserDocument } from "$/types/documents/user"
import type { DeserializedPostResource } from "$/types/documents/post"
import type { DeserializedCommentResource } from "$/types/documents/comment"
import Fetcher from "$@/fetchers/comment"
import isUndefined from "$/type_guards/is_undefined"
import TextualField from "@/fields/non-sensitive_text.vue"
const pageContext = inject("pageContext") as PageContext<"deserialized">
interface CustomEvents {
(event: "createComment", data: DeserializedCommentResource): void
(event: "submitPost"): void
}
const emit = defineEmits<CustomEvents>()
const props = defineProps<{
parentComment?: DeserializedCommentResource,
post: DeserializedPostResource
}>()
const { pageProps } = pageContext
const { userProfile } = pageProps
const post = computed<DeserializedPostResource>(
() => props.post as DeserializedPostResource
)
const parentComment = computed<DeserializedCommentResource|undefined>(
() => props.parentComment as DeserializedCommentResource|undefined
)
const content = ref<string>("")
const fetcher = new Fetcher()
async function submit() {
await fetcher.create({
"approvedAt": null,
"content": content.value,
"deletedAt": null
}, {
"extraDataFields": {
"relationships": {
// eslint-disable-next-line no-undefined
"comments": undefined,
"parentComment": isUndefined(parentComment.value)
// eslint-disable-next-line no-undefined
? undefined
: {
"data": {
"id": parentComment.value.id,
"type": "comment"
}
},
"post": {
"data": {
"id": post.value.id,
"type": "post"
}
},
"user": {
"data": {
"id": userProfile.data.id,
"type": "user"
}
}
}
}
}).then(({ body }) => {
emit("createComment", {
...body.data,
"parentComment": isUndefined(parentComment.value)
// eslint-disable-next-line no-undefined
? undefined
: {
"data": parentComment.value
},
"post": {
"data": post.value
},
"user": userProfile as DeserializedUserDocument
} as DeserializedCommentResource)
})
}
</script>
42 changes: 42 additions & 0 deletions components/comment/multiviewer.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<template>
<div
v-for="(comment, i) in comments"
:key="comment.id"
class="comment">
<Viewer v-model="comments[i]"/>
<br/>
</div>
</template>

<style scoped lang="scss">
</style>

<script setup lang="ts">
import { computed } from "vue"
import type { DeserializedCommentResource } from "$/types/documents/comment"
import Viewer from "@/comment/multiviewer/viewer.vue"
const props = defineProps<{
modelValue: DeserializedCommentResource<"user"|"parentComment">[]
}>()
interface CustomEvents {
(
event: "update:modelValue",
comment: DeserializedCommentResource<"user"|"parentComment">[]
): void
}
const emit = defineEmits<CustomEvents>()
const comments = computed<DeserializedCommentResource<"user"|"parentComment">[]>({
get(): DeserializedCommentResource<"user"|"parentComment">[] {
return props.modelValue
},
set(newValue: DeserializedCommentResource<"user"|"parentComment">[]): void {
emit("update:modelValue", newValue)
}
})
</script>
Loading

0 comments on commit a5985b9

Please sign in to comment.