Add frontend for category picker when admin or thread author
This commit is contained in:
parent
b0639c4da2
commit
cb7418f825
2 changed files with 61 additions and 6 deletions
|
|
@ -14,6 +14,7 @@ when defined(js):
|
||||||
selectedCategoryID*: int
|
selectedCategoryID*: int
|
||||||
loading: bool
|
loading: bool
|
||||||
status: HttpCode
|
status: HttpCode
|
||||||
|
onCategoryChange: proc (oldCategory: Category, newCategory: Category)
|
||||||
|
|
||||||
proc slug(name: string): string =
|
proc slug(name: string): string =
|
||||||
name.strip().replace(" ", "-").toLowerAscii
|
name.strip().replace(" ", "-").toLowerAscii
|
||||||
|
|
@ -40,20 +41,32 @@ when defined(js):
|
||||||
state.loading = true
|
state.loading = true
|
||||||
ajaxGet(makeUri("categories.json"), @[], onCategoryList(state))
|
ajaxGet(makeUri("categories.json"), @[], onCategoryList(state))
|
||||||
|
|
||||||
proc newCategoryPicker*(): CategoryPicker =
|
proc `[]`*(state: CategoryPicker, id: int): Category =
|
||||||
|
state.list.get().categories[id]
|
||||||
|
|
||||||
|
proc newCategoryPicker*(
|
||||||
|
onCategoryChange: proc (oldCategory: Category, newCategory: Category) =
|
||||||
|
proc (oldCategory: Category, newCategory: Category) = discard
|
||||||
|
): CategoryPicker =
|
||||||
result = CategoryPicker(
|
result = CategoryPicker(
|
||||||
list: none[CategoryList](),
|
list: none[CategoryList](),
|
||||||
selectedCategoryID: 0,
|
selectedCategoryID: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
status: Http200
|
status: Http200,
|
||||||
|
onCategoryChange: onCategoryChange
|
||||||
)
|
)
|
||||||
|
|
||||||
|
proc select*(state: CategoryPicker, id: int) =
|
||||||
|
state.selectedCategoryID = id
|
||||||
|
state.markDirty()
|
||||||
|
|
||||||
proc onCategoryClick(state: CategoryPicker, category: Category): proc (ev: Event, n: VNode) =
|
proc onCategoryClick(state: CategoryPicker, category: Category): proc (ev: Event, n: VNode) =
|
||||||
# this is necessary to capture the right value
|
# this is necessary to capture the right value
|
||||||
let cat = category
|
let cat = category
|
||||||
return proc (ev: Event, n: VNode) =
|
return proc (ev: Event, n: VNode) =
|
||||||
state.selectedCategoryID = cat.id
|
let oldCategory = state[state.selectedCategoryID]
|
||||||
state.markDirty()
|
state.select(cat.id)
|
||||||
|
state.onCategoryChange(oldCategory, cat)
|
||||||
|
|
||||||
proc render*(state: CategoryPicker): VNode =
|
proc render*(state: CategoryPicker): VNode =
|
||||||
if state.status != Http200:
|
if state.status != Http200:
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,14 @@ when defined(js):
|
||||||
import karax / [vstyles, kajax, kdom]
|
import karax / [vstyles, kajax, kdom]
|
||||||
|
|
||||||
import karaxutils, error, replybox, editbox, postbutton, delete
|
import karaxutils, error, replybox, editbox, postbutton, delete
|
||||||
|
import categorypicker
|
||||||
|
|
||||||
type
|
type
|
||||||
State = ref object
|
State = ref object
|
||||||
list: Option[PostList]
|
list: Option[PostList]
|
||||||
loading: bool
|
loading: bool
|
||||||
status: HttpCode
|
status: HttpCode
|
||||||
|
error: Option[PostError]
|
||||||
replyingTo: Option[Post]
|
replyingTo: Option[Post]
|
||||||
replyBox: ReplyBox
|
replyBox: ReplyBox
|
||||||
editing: Option[Post] ## If in edit mode, this contains the post.
|
editing: Option[Post] ## If in edit mode, this contains the post.
|
||||||
|
|
@ -33,8 +35,10 @@ when defined(js):
|
||||||
likeButton: LikeButton
|
likeButton: LikeButton
|
||||||
deleteModal: DeleteModal
|
deleteModal: DeleteModal
|
||||||
lockButton: LockButton
|
lockButton: LockButton
|
||||||
|
categoryPicker: CategoryPicker
|
||||||
|
|
||||||
proc onReplyPosted(id: int)
|
proc onReplyPosted(id: int)
|
||||||
|
proc onCategoryChanged(oldCategory: Category, newCategory: Category)
|
||||||
proc onEditPosted(id: int, content: string, subject: Option[string])
|
proc onEditPosted(id: int, content: string, subject: Option[string])
|
||||||
proc onEditCancelled()
|
proc onEditCancelled()
|
||||||
proc onDeletePost(post: Post)
|
proc onDeletePost(post: Post)
|
||||||
|
|
@ -44,17 +48,37 @@ when defined(js):
|
||||||
list: none[PostList](),
|
list: none[PostList](),
|
||||||
loading: false,
|
loading: false,
|
||||||
status: Http200,
|
status: Http200,
|
||||||
|
error: none[PostError](),
|
||||||
replyingTo: none[Post](),
|
replyingTo: none[Post](),
|
||||||
replyBox: newReplyBox(onReplyPosted),
|
replyBox: newReplyBox(onReplyPosted),
|
||||||
editBox: newEditBox(onEditPosted, onEditCancelled),
|
editBox: newEditBox(onEditPosted, onEditCancelled),
|
||||||
likeButton: newLikeButton(),
|
likeButton: newLikeButton(),
|
||||||
deleteModal: newDeleteModal(onDeletePost, onDeleteThread, nil),
|
deleteModal: newDeleteModal(onDeletePost, onDeleteThread, nil),
|
||||||
lockButton: newLockButton()
|
lockButton: newLockButton(),
|
||||||
|
categoryPicker: newCategoryPicker(onCategoryChanged)
|
||||||
)
|
)
|
||||||
|
|
||||||
var
|
var
|
||||||
state = newState()
|
state = newState()
|
||||||
|
|
||||||
|
proc onCategoryPost(httpStatus: int, response: kstring, state: State) =
|
||||||
|
state.loading = false
|
||||||
|
postFinished:
|
||||||
|
discard
|
||||||
|
# TODO: show success message
|
||||||
|
|
||||||
|
proc onCategoryChanged(oldCategory: Category, newCategory: Category) =
|
||||||
|
let uri = makeUri("/updateThread")
|
||||||
|
|
||||||
|
let formData = newFormData()
|
||||||
|
formData.append("threadId", $state.list.get().thread.id)
|
||||||
|
formData.append("category", $newCategory.id)
|
||||||
|
|
||||||
|
state.loading = true
|
||||||
|
|
||||||
|
ajaxPost(uri, @[], cast[cstring](formData),
|
||||||
|
(s: int, r: kstring) => onCategoryPost(s, r, state))
|
||||||
|
|
||||||
proc onPostList(httpStatus: int, response: kstring, postId: Option[int]) =
|
proc onPostList(httpStatus: int, response: kstring, postId: Option[int]) =
|
||||||
state.loading = false
|
state.loading = false
|
||||||
state.status = httpStatus.HttpCode
|
state.status = httpStatus.HttpCode
|
||||||
|
|
@ -66,6 +90,7 @@ when defined(js):
|
||||||
state.list = some(list)
|
state.list = some(list)
|
||||||
|
|
||||||
dom.document.title = list.thread.topic & " - " & dom.document.title
|
dom.document.title = list.thread.topic & " - " & dom.document.title
|
||||||
|
state.categoryPicker.select(list.thread.category.id)
|
||||||
|
|
||||||
# The anchor should be jumped to once all the posts have been loaded.
|
# The anchor should be jumped to once all the posts have been loaded.
|
||||||
if postId.isSome():
|
if postId.isSome():
|
||||||
|
|
@ -179,6 +204,20 @@ when defined(js):
|
||||||
span(class="more-post-count"):
|
span(class="more-post-count"):
|
||||||
text "(" & $post.moreBefore.len & ")"
|
text "(" & $post.moreBefore.len & ")"
|
||||||
|
|
||||||
|
proc genCategories(thread: Thread, currentUser: Option[User]): VNode =
|
||||||
|
let loggedIn = currentUser.isSome()
|
||||||
|
let authoredByUser =
|
||||||
|
loggedIn and currentUser.get().name == thread.author.name
|
||||||
|
let currentAdmin =
|
||||||
|
currentUser.isSome() and currentUser.get().rank == Admin
|
||||||
|
|
||||||
|
result = buildHtml():
|
||||||
|
tdiv():
|
||||||
|
if authoredByUser or currentAdmin:
|
||||||
|
render(state.categoryPicker)
|
||||||
|
else:
|
||||||
|
render(thread.category)
|
||||||
|
|
||||||
proc genPostButtons(post: Post, currentUser: Option[User]): Vnode =
|
proc genPostButtons(post: Post, currentUser: Option[User]): Vnode =
|
||||||
let loggedIn = currentUser.isSome()
|
let loggedIn = currentUser.isSome()
|
||||||
let authoredByUser =
|
let authoredByUser =
|
||||||
|
|
@ -330,6 +369,9 @@ when defined(js):
|
||||||
result = buildHtml():
|
result = buildHtml():
|
||||||
section(class="container grid-xl"):
|
section(class="container grid-xl"):
|
||||||
tdiv(id="thread-title", class="title"):
|
tdiv(id="thread-title", class="title"):
|
||||||
|
if state.error.isSome():
|
||||||
|
span(class="text-error"):
|
||||||
|
text state.error.get().message
|
||||||
p(): text list.thread.topic
|
p(): text list.thread.topic
|
||||||
if list.thread.isLocked:
|
if list.thread.isLocked:
|
||||||
italic(class="fas fa-lock fa-xs",
|
italic(class="fas fa-lock fa-xs",
|
||||||
|
|
@ -343,7 +385,7 @@ when defined(js):
|
||||||
italic(class="fas fa-check-square fa-xs",
|
italic(class="fas fa-check-square fa-xs",
|
||||||
title="Thread has a solution")
|
title="Thread has a solution")
|
||||||
text "Solved"
|
text "Solved"
|
||||||
render(list.thread.category)
|
genCategories(list.thread, currentUser)
|
||||||
tdiv(class="posts"):
|
tdiv(class="posts"):
|
||||||
var prevPost: Option[Post] = none[Post]()
|
var prevPost: Option[Post] = none[Post]()
|
||||||
for i, post in list.posts:
|
for i, post in list.posts:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue