Implements simple stats in profile view.
This commit is contained in:
parent
d345bf76ae
commit
2dd9dd52a2
4 changed files with 135 additions and 10 deletions
10
forum.nim
10
forum.nim
|
|
@ -1015,10 +1015,10 @@ template createTFD() =
|
|||
|
||||
#[ DB functions. TODO: Move to another module? ]#
|
||||
|
||||
proc selectUser(userRow: seq[string]): threadlist.User =
|
||||
proc selectUser(userRow: seq[string], avatarSize: int=80): threadlist.User =
|
||||
return threadlist.User(
|
||||
name: userRow[0],
|
||||
avatarUrl: userRow[1].getGravatarUrl(),
|
||||
avatarUrl: userRow[1].getGravatarUrl(avatarSize),
|
||||
lastOnline: userRow[2].parseInt,
|
||||
rank: parseEnum[Rank](userRow[3])
|
||||
)
|
||||
|
|
@ -1216,7 +1216,8 @@ routes:
|
|||
|
||||
let postsQuery = sql("""
|
||||
select p.id, p.content, strftime('%s', p.creation), p.author,
|
||||
u.name, u.email, strftime('%s', u.lastOnline), u.status
|
||||
u.name, u.email, strftime('%s', u.lastOnline), u.status,
|
||||
strftime('%s', u.creation)
|
||||
from post p, person u
|
||||
where u.id = p.author and u.name = ?
|
||||
order by p.id desc;
|
||||
|
|
@ -1230,7 +1231,8 @@ routes:
|
|||
let rows = db.getAllRows(postsQuery, username)
|
||||
profile.user = selectUser(@[
|
||||
rows[0][4], rows[0][5], rows[0][6], rows[0][7]
|
||||
])
|
||||
], avatarSize=200)
|
||||
profile.joinTime = rows[0][8].parseInt()
|
||||
|
||||
if c.rank >= Admin:
|
||||
profile.email = some(rows[0][5])
|
||||
|
|
|
|||
|
|
@ -4,16 +4,18 @@ from dom import window, Location
|
|||
include karax/prelude
|
||||
import jester/patterns
|
||||
|
||||
import threadlist, postlist, header
|
||||
import threadlist, postlist, header, profile
|
||||
import karaxutils
|
||||
|
||||
type
|
||||
State = ref object
|
||||
url: Location
|
||||
profile: ProfileState
|
||||
|
||||
proc newState(): State =
|
||||
State(
|
||||
url: window.location
|
||||
url: window.location,
|
||||
profile: newProfileState()
|
||||
)
|
||||
|
||||
var state = newState()
|
||||
|
|
@ -44,7 +46,11 @@ proc render(): VNode =
|
|||
result = buildHtml(tdiv()):
|
||||
renderHeader()
|
||||
route([
|
||||
r("/t/@id?",
|
||||
r("/profile/@username",
|
||||
(params: Params) =>
|
||||
(render(state.profile, params["username"]))
|
||||
),
|
||||
r("/t/@id",
|
||||
(params: Params) =>
|
||||
(renderPostList(params["id"].parseInt(), isLoggedIn()))
|
||||
),
|
||||
|
|
|
|||
|
|
@ -449,4 +449,54 @@ hr {
|
|||
border: 0;
|
||||
}
|
||||
|
||||
@import "syntax.scss";
|
||||
@import "syntax.scss";
|
||||
|
||||
// - Profile view
|
||||
|
||||
.profile {
|
||||
@extend .tile;
|
||||
margin-top: $control-padding-y*5;
|
||||
}
|
||||
|
||||
.profile-icon {
|
||||
@extend .tile-icon;
|
||||
}
|
||||
|
||||
.profile-avatar {
|
||||
@extend .avatar;
|
||||
@extend .avatar-xl;
|
||||
|
||||
height: 8.2rem;
|
||||
width: 8.2rem;
|
||||
}
|
||||
|
||||
.profile-content {
|
||||
@extend .tile-content;
|
||||
padding: $control-padding-x $control-padding-y;
|
||||
}
|
||||
|
||||
.profile-title {
|
||||
@extend .tile-title;
|
||||
}
|
||||
|
||||
.profile-stats {
|
||||
dl {
|
||||
border-top: 1px solid $border-color;
|
||||
border-bottom: 1px solid $border-color;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: normal;
|
||||
color: lighten($dark-color, 15%);
|
||||
}
|
||||
|
||||
dt, dd {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
margin-right: $control-padding-x;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-right: $control-padding-x-lg;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import options
|
||||
import threadlist, post
|
||||
import options, httpcore, json, sugar
|
||||
|
||||
import threadlist, post, category, error
|
||||
type
|
||||
Profile* = object
|
||||
user*: User
|
||||
|
|
@ -9,3 +10,69 @@ type
|
|||
# Information that only admins should see.
|
||||
email*: Option[string]
|
||||
|
||||
when defined(js):
|
||||
include karax/prelude
|
||||
import karax/[kajax]
|
||||
import karaxutils
|
||||
|
||||
type
|
||||
ProfileState* = ref object
|
||||
profile: Option[Profile]
|
||||
loading: bool
|
||||
status: HttpCode
|
||||
|
||||
proc newProfileState*(): ProfileState =
|
||||
ProfileState(
|
||||
loading: false,
|
||||
status: Http200
|
||||
)
|
||||
|
||||
proc onProfile(httpStatus: int, response: kstring, state: ProfileState) =
|
||||
# TODO: Try to abstract these.
|
||||
state.loading = false
|
||||
state.status = httpStatus.HttpCode
|
||||
if state.status != Http200: return
|
||||
|
||||
let parsed = parseJson($response)
|
||||
let profile = to(parsed, Profile)
|
||||
|
||||
state.profile = some(profile)
|
||||
|
||||
proc render*(state: ProfileState, username: string): VNode =
|
||||
if state.status != Http200:
|
||||
return renderError("Couldn't retrieve profile.")
|
||||
|
||||
if state.profile.isNone:
|
||||
let uri = makeUri("profile.json", ("username", username))
|
||||
ajaxGet(uri, @[], (s: int, r: kstring) => onProfile(s, r, state))
|
||||
|
||||
return buildHtml(tdiv(class="loading loading-lg"))
|
||||
|
||||
let profile = state.profile.get()
|
||||
result = buildHtml():
|
||||
section(class="container grid-xl"):
|
||||
tdiv(class="profile"):
|
||||
tdiv(class="profile-icon"):
|
||||
render(profile.user, "profile-avatar")
|
||||
tdiv(class="profile-content"):
|
||||
h2(class="profile-title"):
|
||||
text profile.user.name
|
||||
|
||||
tdiv(class="profile-stats"):
|
||||
dl():
|
||||
dt(text "Joined")
|
||||
dd(text threadlist.renderActivity(profile.joinTime))
|
||||
dt(text "Last Post")
|
||||
dd(text renderActivity(profile.posts[0].info.creation))
|
||||
dt(text "Last Online")
|
||||
dd(text renderActivity(profile.user.lastOnline))
|
||||
dt(text "Rank")
|
||||
dd(text $profile.user.rank)
|
||||
|
||||
tdiv(class="columns"):
|
||||
tdiv(class="column col-6"):
|
||||
h4(text "Latest Posts")
|
||||
tdiv(class="column col-6"):
|
||||
h4(text "Latest Threads")
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue