Skip to content

Commit

Permalink
Feat: update post. (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
luanbt21 authored Dec 3, 2022
1 parent ee39f5d commit 880f7e0
Show file tree
Hide file tree
Showing 15 changed files with 255 additions and 127 deletions.
4 changes: 2 additions & 2 deletions prisma/dbml/schema.dbml
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ Table Item {

Table Post {
id String [pk]
title String
description String
title String [not null]
description String [not null]
audios String[] [not null]
images String[] [not null]
videos String[] [not null]
Expand Down
4 changes: 2 additions & 2 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ model Item {

model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String?
description String?
title String
description String
audios String[]
images String[]
videos String[]
Expand Down
1 change: 1 addition & 0 deletions src/i18n/en/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const en: Translation = {
done: 'Done',
create: 'Create',
by: 'By',
update: 'Update',
}

export default en
8 changes: 8 additions & 0 deletions src/i18n/i18n-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ type RootTranslation = {
* B​y
*/
by: string
/**
* U​p​d​a​t​e
*/
update: string
}

export type TranslationFunctions = {
Expand Down Expand Up @@ -506,6 +510,10 @@ export type TranslationFunctions = {
* By
*/
by: () => LocalizedString
/**
* Update
*/
update: () => LocalizedString
}

export type Formatters = {}
3 changes: 2 additions & 1 deletion src/i18n/vi/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ const vi: BaseTranslation = {
newCollection: 'Bộ sưu tập mới',
done: 'Xong',
create: 'Tạo',
by: 'Bởi'
by: 'Bởi',
update: 'Cập nhật',
}

export default vi
4 changes: 2 additions & 2 deletions src/lib/components/CreatePostModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
<form
id="create-post-form"
class="flex flex-col gap-y-2"
action={`/${$locale}/post?/create`}
action="/{$locale}/post?/create"
method="POST"
enctype="multipart/form-data"
>
Expand All @@ -134,7 +134,7 @@
<div class="tooltip" data-tip={item.dataTip()}>
<label class="btn btn-ghost btn-square btn-sm" tabindex="0">
<svg class="remix w-full h-full fill-current">
<use href="{remixiconUrl}#ri-${item.icon}" />
<use href="{remixiconUrl}#ri-{item.icon}" />
</svg>
{media?.[item.name] ? media[item.name]?.length : ''}
<input
Expand Down
55 changes: 22 additions & 33 deletions src/lib/components/CreateQuestion.svelte
Original file line number Diff line number Diff line change
@@ -1,62 +1,51 @@
<script lang="ts">
import remixiconUrl from 'remixicon/fonts/remixicon.symbol.svg'
import { LL } from '$i18n/i18n-svelte'
import type { Option } from '@prisma/client'
export let isQuestionOk: boolean
export let options: Option[] | null = null
let rightOption: string
let options: { id: string; value: string; isDuplicated: boolean }[] = [
{
id: crypto.randomUUID(),
value: '',
isDuplicated: false,
},
{
id: crypto.randomUUID(),
value: '',
isDuplicated: false,
},
]
let rightOption: string | undefined = options?.find(({ type }) => !!type)?.value
const initOption = (value = '') => ({ id: crypto.randomUUID(), value, isDuplicated: false })
let optionsInput: { id: string; value: string; isDuplicated: boolean }[] = options?.length
? options.map(({ value }) => initOption(value))
: [initOption(), initOption()]
$: isQuestionOk =
options.length > 0 &&
!options.some((option) => !option.value || option.isDuplicated) &&
optionsInput.length > 0 &&
!optionsInput.some((option) => !option.value || option.isDuplicated) &&
!!rightOption
const addOption = () => {
options = [
...options,
{
id: crypto.randomUUID(),
value: '',
isDuplicated: false,
},
]
optionsInput = [...optionsInput, initOption()]
}
let id: number
const checkDuplicate = () => {
if (id) clearTimeout(id)
id = window.setTimeout(() => {
out: for (let i = 0; i < options.length; i++) {
out: for (let i = 0; i < optionsInput.length; i++) {
let isDuplicated = false
for (let j = 0; j < options.length; j++) {
for (let j = 0; j < optionsInput.length; j++) {
if (i === j) continue
if (options[j].value === '') continue
if (options[i].value === options[j].value) {
options[i].isDuplicated = true
options[j].isDuplicated = true
if (optionsInput[j].value === '') continue
if (optionsInput[i].value === optionsInput[j].value) {
optionsInput[i].isDuplicated = true
optionsInput[j].isDuplicated = true
continue out
}
}
options[i].isDuplicated = isDuplicated
optionsInput[i].isDuplicated = isDuplicated
}
}, 100)
}
</script>

<div class="flex flex-col gap-y-2">
{#each options as option, i (option.id)}
{#each optionsInput as option, i (option.id)}
<div class="form-control">
<div class="flex gap-x-2 items-end">
<div class="w-full">
Expand All @@ -70,7 +59,7 @@
type="button"
class="btn btn-ghost btn-sm normal-case"
on:click={() => {
options = options.filter((o) => o.id !== option.id)
optionsInput = optionsInput.filter((o) => o.id !== option.id)
}}
>
{$LL.remove()}
Expand Down Expand Up @@ -105,7 +94,7 @@
</div>
</div>
{/each}
{#if options.length < 4}
{#if optionsInput.length < 4}
<button type="button" class="btn btn-outline btn-sm normal-case mt-4" on:click={addOption}>
<svg class="remix w-5 h-5 fill-current">
<use href="{remixiconUrl}#ri-add-fill" />
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/PostAction.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

<form
method="POST"
action={`/${$locale}/post?/${action}`}
action="/{$locale}/post?/{action}"
use:enhance={({ cancel }) => {
if (!$user) {
$showLoginModal = true
Expand Down
7 changes: 1 addition & 6 deletions src/lib/components/SearchBox.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,7 @@
}
</script>

<form
action={`/${$locale}/search`}
on:submit|preventDefault={() => {
goto(`/${$locale}/search?q=${q}`)
}}
>
<form action="/{$locale}/search">
<div class="form-control">
<div class="dropdown dropdown-end">
<input
Expand Down
128 changes: 128 additions & 0 deletions src/lib/components/UpdatePostModal.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<script lang="ts">
import remixiconUrl from 'remixicon/fonts/remixicon.symbol.svg'
import Tiptap from '$components/Tiptap'
import CreateQuestion from '$components/CreateQuestion.svelte'
import { locale, LL } from '$i18n/i18n-svelte'
import { user } from '$stores/auth'
import type { Option, Post } from '@prisma/client'
import { enhance } from '$app/forms'
import { toastError, toastSuccess } from '$utils/client'
import type { ActionResult } from '@sveltejs/kit'
export let id: string
export let postId: string
export let title: string
export let description: string
export let options: Option[]
export let updateUI: (data: Pick<Post, 'title' | 'description' | 'options'>) => void
let isQuestion = !!options.length
let isQuestionOk = false
let loading = false
$: isFormOk = isQuestion ? title && description && isQuestionOk : title && description
const handleSubmit = () => {
loading = true
return ({ result }: { result: ActionResult<Record<string, any>, Record<string, any>> }) => {
if (result.type === 'success') {
toastSuccess('Update post successfully')
document.getElementById(id)?.click()
updateUI(result.data as Pick<Post, 'title' | 'description' | 'options'>)
} else {
toastError('Update post failed')
loading = false
}
}
}
</script>

{#if $user}
<div class="modal w-full">
<div class="modal-box relative w-full max-w-4xl">
<label for={id} class="btn btn-sm btn-circle absolute right-2 top-2">✕</label>
<h3 class="text-lg font-bold">{$LL.startAPost()}</h3>
<div class="divider" />

<div class="flex flex-col gap-y-2">
<div class="flex items-center">
<div class="avatar">
<div class="w-12 rounded-full">
<img src={$user.photoURL} alt="user avatar" />
</div>
</div>
<div class="ml-2 w-full">
<div class="font-semibold text-lg">
{$user.displayName}
</div>
</div>
</div>

<div class="form-control w-full">
<input
form="update-post-form"
type="text"
name="title"
placeholder={$LL.title()}
class="input input-bordered w-full text-lg"
maxlength="100"
required
bind:value={title}
/>
</div>

<Tiptap bind:value={description} placeholder={$LL.startAPost()} className="min-h-16" />

<form
id="update-post-form"
class="flex flex-col gap-y-2"
action="/{$locale}/post?/update"
method="POST"
enctype="multipart/form-data"
use:enhance={handleSubmit}
>
<input type="hidden" name="postId" value={postId} />
<input type="hidden" name="description" value={description} />
{#if isQuestion}
<div class="relative border rounded-lg px-2 py-4">
<button
type="button"
class="btn btn-sm btn-circle absolute right-2 top-2"
on:click={() => (isQuestion = false)}
>
</button>
<CreateQuestion bind:isQuestionOk {options} />
</div>
{/if}

<div class="flex items-center flex-wrap justify-between mx-3">
<div class="flex flex-wrap gap-x-2">
{#if !isQuestion}
<div class="tooltip" data-tip={$LL.addMultipleChoice()}>
<button
type="button"
class="btn btn-ghost btn-square btn-sm"
on:click={() => (isQuestion = true)}
>
<svg class="remix w-full h-full fill-current">
<use href="{remixiconUrl}#ri-checkbox-multiple-fill" />
</svg>
</button>
</div>
{/if}
</div>

<button
type="submit"
class="btn btn-primary ml-auto"
class:loading
disabled={!isFormOk}
>
{$LL.update()}
</button>
</div>
</form>
</div>
</div>
</div>
{/if}
39 changes: 0 additions & 39 deletions src/lib/db/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,45 +44,6 @@ export const getPosts = async ({
})
}

export const savePost = async (post: Post & { tags: string[] }) => {
const { tags, ...data } = post
const tagsId = []
for (const t of tags) {
tagsId.push(
await prisma.tag.upsert({
where: {
name: t,
},
update: {},
create: {
name: t,
description: '',
},
select: {
id: true,
},
}),
)
}
prisma.post.create({
data: {
...data,
tags: {
connect: tagsId,
},
},
})
}

export const updatePost = async (post: Post) => {
return prisma.post.update({
where: {
id: post.id,
},
data: post,
})
}

export const deletePost = async (id: string) => {
return prisma.post.delete({
where: {
Expand Down
Loading

0 comments on commit 880f7e0

Please sign in to comment.