f0e69f78da
* Add an Admin Certification Photo workflow where we can request the user to upload a secondary form of ID (government issued photo ID showing their face and date of birth). * An admin rejection option can request secondary photo ID. * It sends a distinct e-mail to the user apart from the regular rejection email * It flags their cert photo as "Secondary Needed" forever: even if the user removes their cert photo and starts from scratch, it will immediately request secondary ID when uploading a new primary photo. * Secondary photos are deleted from the server on both Approve and Reject by the admin account, for user privacy. * If approved, a Secondary Approved=true boolean is stored in the database. This boolean is set to False if the user deletes their cert photo in the future.
842 lines
49 KiB
HTML
842 lines
49 KiB
HTML
{{define "title"}}My Dashboard{{end}}
|
|
{{define "content"}}
|
|
<div class="container">
|
|
<section class="hero is-info is-bold">
|
|
<div class="hero-body">
|
|
<div class="container">
|
|
<h1 class="title">User Dashboard</h1>
|
|
<h2 class="subtitle">to your account</h2>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="block p-4">
|
|
<div class="columns">
|
|
<div class="column">
|
|
<!-- Onboarding Checklist -->
|
|
{{if or (not .CurrentUser.Certified) (not .CurrentUser.ProfilePhoto.ID)}}
|
|
<div class="card block">
|
|
<header class="card-header has-background-danger">
|
|
<p class="card-header-title has-text-light">
|
|
<span class="icon"><i class="fa fa-check"></i></span>
|
|
<span>Onboarding Checklist</span>
|
|
</p>
|
|
</header>
|
|
|
|
<div class="card-content">
|
|
<p class="block">
|
|
You're almost there! Please review the following checklist items to gain
|
|
full access to this website. Members are expected to have a face picture
|
|
as their default Profile Pic and upload a Verification Photo to become
|
|
certified as being a real person.
|
|
</p>
|
|
|
|
<ul class="menu-list block">
|
|
<li>
|
|
<a href="/photo/upload?intent=profile_pic">
|
|
<div class="columns is-mobile is-gapless">
|
|
<div class="column is-narrow mr-2">
|
|
{{if .CurrentUser.ProfilePhoto.ID}}
|
|
<span class="icon"><i class="fa fa-circle-check has-text-success"></i></span>
|
|
{{else}}
|
|
<span class="icon"><i class="fa fa-circle-xmark has-text-danger"></i></span>
|
|
{{end}}
|
|
</div>
|
|
<div class="column">
|
|
Upload a Profile Picture to your account that shows your face
|
|
|
|
<p class="help">
|
|
Click here to upload a new profile picture
|
|
<i class="fa fa-external-link ml-1"></i>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</li>
|
|
|
|
<li>
|
|
<a href="/photo/certification">
|
|
<div class="columns is-mobile is-gapless">
|
|
<div class="column is-narrow mr-2">
|
|
{{if .CurrentUser.Certified}}
|
|
<span class="icon"><i class="fa fa-circle-check has-text-success"></i></span>
|
|
{{else}}
|
|
<span class="icon"><i class="fa fa-circle-xmark has-text-danger"></i></span>
|
|
{{end}}
|
|
</div>
|
|
<div class="column">
|
|
Get certified by uploading a verification selfie
|
|
|
|
<p class="help">
|
|
Click here to go to the Certification Photo upload page
|
|
<i class="fa fa-external-link ml-1"></i>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
|
|
<!-- "Very Private" Restricted Account warning for certified users -->
|
|
{{if and .CurrentUser.Certified .IsShyUser}}
|
|
<div class="card block">
|
|
<header class="card-header has-background-danger">
|
|
<p class="card-header-title has-text-light">
|
|
<span class="icon"><i class="fa fa-exclamation-triangle"></i></span>
|
|
<span>Your profile page is too private</span>
|
|
</p>
|
|
</header>
|
|
|
|
<div class="card-content">
|
|
<p class="block">
|
|
You are considered to be a <strong>Shy Account</strong> because your profile and
|
|
photos are all set to Private or Friends-only visibility, so that to other members
|
|
of {{PrettyTitle}} you appear like a blank, faceless profile.
|
|
</p>
|
|
|
|
<p class="block">
|
|
While in this restricted state, you are grouped into a cohort with other members who
|
|
are as shy as you are and have limited contact options to connect with our other,
|
|
{{PrettyTitle}} members who are sharing their nudes on public.
|
|
</p>
|
|
|
|
<p class="block">
|
|
<a href="/faq#shy-faqs">Click here to learn more</a> about your Shy Account. To
|
|
remedy this, please see the following steps:
|
|
</p>
|
|
|
|
<ul class="menu-list block">
|
|
<li>
|
|
<a href="/settings">
|
|
{{if eq .CurrentUser.Visibility "public"}}
|
|
<span class="icon"><i class="fa fa-circle-check has-text-success"></i></span>
|
|
{{else}}
|
|
<span class="icon"><i class="fa fa-circle has-text-danger"></i></span>
|
|
{{end}}
|
|
<span>
|
|
Have your profile visibility set to <strong>Public</strong>.
|
|
{{if not (eq .CurrentUser.Visibility "public")}}
|
|
<span class="icon"><i class="fa fa-external-link"></i></span>
|
|
{{end}}
|
|
</span>
|
|
</a>
|
|
</li>
|
|
|
|
<li>
|
|
<a href="/u/{{.CurrentUser.Username}}/photos">
|
|
{{if .HasPublicPhoto}}
|
|
<span class="icon"><i class="fa fa-circle-check has-text-success"></i></span>
|
|
{{else}}
|
|
<span class="icon"><i class="fa fa-circle has-text-danger"></i></span>
|
|
{{end}}
|
|
<span>
|
|
Have at least one <strong>Public</strong> photo on your profile.
|
|
{{if not .HasPublicPhoto}}
|
|
<span class="icon"><i class="fa fa-external-link"></i></span>
|
|
{{end}}
|
|
</span>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
|
|
<!-- New Feature -->
|
|
{{if not (.CurrentUser.GetProfileField "hero-color-start")}}
|
|
<div class="card block">
|
|
<header class="card-header has-background-success">
|
|
<p class="card-header-title has-text-light">
|
|
<i class="fa fa-gift mr-2"></i>
|
|
New Feature: Profile Look & Feel
|
|
</p>
|
|
</header>
|
|
|
|
<div class="card-content">
|
|
<p class="block">
|
|
A new feature is now available:
|
|
<a href="/settings#look">customize your profile page look & feel!</a>
|
|
</p>
|
|
|
|
<p class="block">
|
|
You can now personalize your profile page with a custom color scheme for
|
|
your header and profile cards. In the future, it will also be possible to
|
|
set a custom wallpaper background image and stylize your profile page
|
|
even further!
|
|
</p>
|
|
|
|
<p class="block">
|
|
Check it out on your Settings > <a href="/settings#look">Look & Feel</a>
|
|
page!
|
|
</p>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
|
|
<div class="card block">
|
|
<header class="card-header has-background-link">
|
|
<p class="card-header-title has-text-light">My Account</p>
|
|
</header>
|
|
|
|
<div class="card-content">
|
|
<aside class="menu">
|
|
<ul class="menu-list">
|
|
<li>
|
|
<a href="/u/{{.CurrentUser.Username}}">
|
|
<span class="icon"><i class="fa fa-user"></i></span>
|
|
My Profile
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<a href="/u/{{.CurrentUser.Username}}/photos">
|
|
<span class="icon"><i class="fa fa-image"></i></span>
|
|
My Photos
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<a href="/photo/upload">
|
|
<span class="icon"><i class="fa fa-upload"></i></span>
|
|
Upload Photos
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<a href="/photo/private">
|
|
<span class="icon"><i class="fa fa-eye"></i></span>
|
|
Manage Private Photos
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<a href="/settings">
|
|
<span class="icon"><i class="fa fa-edit"></i></span>
|
|
Edit Profile & Settings
|
|
</a>
|
|
</li>
|
|
{{if .CurrentUser.IsInnerCircle}}
|
|
<li>
|
|
<a href="/inner-circle">
|
|
<span class="icon"><img src="/static/img/circle-16.png"></span>
|
|
{{PrettyCircle}}
|
|
</a>
|
|
</li>
|
|
{{end}}
|
|
<li>
|
|
<a href="/photo/certification">
|
|
<span class="icon"><i class="fa fa-certificate"></i></span>
|
|
Certification Photo
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<a href="/users/blocked">
|
|
<span class="icon"><i class="fa fa-hand"></i></span>
|
|
Blocked Users
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<a href="/notes/me">
|
|
<span class="icon"><i class="fa fa-pen-to-square mr-1"></i></span>
|
|
My User Notes
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<a href="/logout">
|
|
<span class="icon"><i class="fa fa-arrow-right-from-bracket"></i></span>
|
|
Log out
|
|
</a>
|
|
</li>
|
|
{{if .SessionImpersonated}}
|
|
<li>
|
|
<a href="/admin/unimpersonate" class="has-text-danger">
|
|
<span class="icon"><i class="fa fa-ghost"></i></span>
|
|
<span>Unimpersonate</span>
|
|
</a>
|
|
</li>
|
|
{{end}}
|
|
<li>
|
|
<a href="/settings#deactivate">
|
|
<span class="icon"><i class="fa fa-trash"></i></span>
|
|
Delete account
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</aside>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{$Root := .}}
|
|
|
|
<div class="column">
|
|
<div class="card" id="notifications">
|
|
<header class="card-header has-background-warning">
|
|
<p class="card-header-title">Notifications</p>
|
|
</header>
|
|
|
|
<div class="card-content">
|
|
<!-- Notifications header row: tablets on upwards -->
|
|
<div class="is-hidden-mobile">
|
|
<form method="POST" action="{{.Request.URL.Path}}">
|
|
{{InputCSRF}}
|
|
<div class="columns mb-2">
|
|
<div class="column">
|
|
{{if gt .NavUnreadNotifications 0}}
|
|
{{.NavUnreadNotifications}} unread notification{{Pluralize64 .NavUnreadNotifications}}.
|
|
{{else}}
|
|
No unread notifications.
|
|
{{end}}
|
|
</div>
|
|
<div class="column is-narrow has-text-right">
|
|
<button type="submit" name="intent" value="clear-all"
|
|
class="button is-danger is-light is-small"
|
|
onclick="return window.confirm('Are you sure you want to REMOVE all notifications?')"
|
|
title="Remove all notifications from your feed">
|
|
<i class="fa fa-xmark mr-1"></i>
|
|
Clear all
|
|
</button>
|
|
|
|
<button type="submit" name="intent" value="read-notifications"
|
|
class="button is-link is-light is-small">
|
|
<i class="fa fa-check mr-1"></i>
|
|
Mark all as read
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Notifications header: for mobiles only version -->
|
|
<div class="is-hidden-tablet">
|
|
<p>
|
|
{{if gt .NavUnreadNotifications 0}}
|
|
{{.NavUnreadNotifications}} unread notification{{Pluralize64 .NavUnreadNotifications}}.
|
|
{{else}}
|
|
No unread notifications.
|
|
{{end}}
|
|
</p>
|
|
<form method="POST" action="{{.Request.URL.Path}}">
|
|
{{InputCSRF}}
|
|
<div class="my-2 has-text-right">
|
|
<button type="submit" name="intent" value="clear-all"
|
|
class="button is-danger is-light is-small"
|
|
onclick="return window.confirm('Are you sure you want to REMOVE all notifications?')">
|
|
<i class="fa fa-xmark mr-1"></i>
|
|
Clear all
|
|
</button>
|
|
|
|
<button type="submit" name="intent" value="read-notifications"
|
|
class="button is-link is-light is-small">
|
|
<i class="fa fa-check mr-1"></i>
|
|
Mark all as read
|
|
</button>
|
|
</div>
|
|
</form>
|
|
<hr>
|
|
</div>
|
|
|
|
<!-- Filters -->
|
|
<div class="block">
|
|
<form action="{{.Request.URL.Path}}" method="GET">
|
|
|
|
<div class="card nonshy-collapsible-mobile nonshy-collapsible-always mb-5">
|
|
<header class="card-header has-background-link-light">
|
|
<p class="card-header-title has-text-dark">
|
|
<i class="fa fa-list mr-2"></i> Notification Types
|
|
</p>
|
|
<button class="card-header-icon" type="button">
|
|
<span class="icon">
|
|
<i class="fa fa-angle-up"></i>
|
|
</span>
|
|
</button>
|
|
</header>
|
|
<div class="card-content">
|
|
|
|
<p class="block">
|
|
<a href="/settings#notifications">
|
|
<i class="fa fa-gear mr-1"></i>
|
|
Manage notification settings
|
|
</a>
|
|
</p>
|
|
|
|
<div class="columns is-multiline mb-0">
|
|
|
|
<div class="column is-half">
|
|
<div class="field">
|
|
<label class="checkbox">
|
|
<input type="checkbox"
|
|
name="likes"
|
|
value="true"
|
|
{{if .Filters.Likes}}checked{{end}}
|
|
>
|
|
Likes
|
|
<p class="help">
|
|
on your photos, profile or comments
|
|
</p>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column is-half">
|
|
<div class="field">
|
|
<label class="checkbox">
|
|
<input type="checkbox"
|
|
name="comments"
|
|
value="true"
|
|
{{if .Filters.Comments}}checked{{end}}
|
|
>
|
|
Comments
|
|
<p class="help">
|
|
on your photos
|
|
</p>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column is-half">
|
|
<div class="field">
|
|
<label class="checkbox">
|
|
<input type="checkbox"
|
|
name="photos"
|
|
value="true"
|
|
{{if .Filters.NewPhotos}}checked{{end}}
|
|
>
|
|
New Photos
|
|
<p class="help">
|
|
of your friends
|
|
</p>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column is-half">
|
|
<div class="field">
|
|
<label class="checkbox">
|
|
<input type="checkbox"
|
|
name="replies"
|
|
value="true"
|
|
{{if .Filters.AlsoCommented}}checked{{end}}
|
|
>
|
|
Replies
|
|
<p class="help">
|
|
on comment threads you follow
|
|
</p>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column is-half">
|
|
<div class="field">
|
|
<label class="checkbox">
|
|
<input type="checkbox"
|
|
name="private"
|
|
value="true"
|
|
{{if .Filters.PrivatePhoto}}checked{{end}}
|
|
>
|
|
Private photos
|
|
<p class="help">
|
|
unlock notifications
|
|
</p>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column is-half">
|
|
<div class="field">
|
|
<label class="checkbox">
|
|
<input type="checkbox"
|
|
name="misc"
|
|
value="true"
|
|
{{if .Filters.Misc}}checked{{end}}
|
|
>
|
|
Miscellaneous
|
|
<p class="help">
|
|
new friends, certification photos, etc.
|
|
</p>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="block has-text-centered">
|
|
<a href="{{.Request.URL.Path}}" class="button">
|
|
Reset
|
|
</a>
|
|
<button type="submit" class="button is-success">
|
|
Apply Filters
|
|
</button>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<table class="table is-striped is-fullwidth is-hoverable">
|
|
<tbody>
|
|
{{range .Notifications}}
|
|
{{$Body := $Root.NotifMap.Get .ID}}
|
|
<tr>
|
|
<td class="nonshy-notification-row" data-notification-id="{{.ID}}">
|
|
<div class="columns">
|
|
<div class="column is-narrow has-text-centered">
|
|
{{if not .Read}}
|
|
<div class="mb-2 nonshy-notification-new">
|
|
<strong class="tag is-success">NEW!</strong>
|
|
</div>
|
|
{{end}}
|
|
<a href="/u/{{.AboutUser.Username}}">
|
|
{{template "avatar-48x48" .AboutUser}}
|
|
</a>
|
|
</div>
|
|
<div class="column">
|
|
<div class="mb-1">
|
|
{{if eq .Type "like"}}
|
|
<span class="icon"><i class="fa fa-heart has-text-danger"></i></span>
|
|
<span>
|
|
<a href="/u/{{.AboutUser.Username}}"><strong>{{.AboutUser.Username}}</strong></a>
|
|
liked your
|
|
{{if eq .TableName "photos"}}
|
|
{{if $Body.Photo}}
|
|
<a href="/photo/view?id={{$Body.Photo.ID}}">photo</a>.
|
|
{{else}}
|
|
photo.
|
|
{{end}}
|
|
{{else if eq .TableName "users"}}
|
|
profile page.
|
|
{{else if eq .TableName "comments"}}
|
|
{{if .Link}}
|
|
<a href="{{.Link}}">comment</a>:
|
|
{{else}}
|
|
comment.
|
|
{{end}}
|
|
{{else}}
|
|
{{.TableName}}.
|
|
{{end}}
|
|
</span>
|
|
{{else if eq .Type "comment"}}
|
|
<span class="icon"><i class="fa fa-comment has-text-success"></i></span>
|
|
<span>
|
|
<a href="/u/{{.AboutUser.Username}}"><strong>{{.AboutUser.Username}}</strong></a>
|
|
commented on your
|
|
<a href="{{.Link}}">
|
|
{{if eq .TableName "photos"}}
|
|
photo:
|
|
{{else}}
|
|
{{.TableName}}:
|
|
{{end}}
|
|
</a>
|
|
</span>
|
|
{{else if eq .Type "also_comment"}}
|
|
<span class="icon"><i class="fa fa-comment has-text-success"></i></span>
|
|
<span>
|
|
<a href="/u/{{.AboutUser.Username}}"><strong>{{.AboutUser.Username}}</strong></a>
|
|
also commented on a
|
|
<a href="{{.Link}}">
|
|
{{if eq .TableName "photos"}}
|
|
photo
|
|
{{else}}
|
|
{{.TableName}}
|
|
{{end}}
|
|
</a>
|
|
that you replied to:
|
|
</span>
|
|
{{else if eq .Type "also_posted"}}
|
|
<span class="icon"><i class="fa fa-comments has-text-success"></i></span>
|
|
<span>
|
|
<a href="/u/{{.AboutUser.Username}}"><strong>{{.AboutUser.Username}}</strong></a>
|
|
replied to <a href="{{.Link}}">a forum thread</a> that you follow:
|
|
</span>
|
|
{{else if eq .Type "friendship_approved"}}
|
|
<span class="icon"><i class="fa fa-user-group has-text-success"></i></span>
|
|
<span>
|
|
<a href="/u/{{.AboutUser.Username}}"><strong>{{.AboutUser.Username}}</strong></a>
|
|
accepted your friend request!
|
|
</span>
|
|
{{else if eq .Type "private_photo"}}
|
|
<span class="icon"><i class="fa fa-unlock has-text-private"></i></span>
|
|
<span>
|
|
<a href="/u/{{.AboutUser.Username}}"><strong>{{.AboutUser.Username}}</strong></a>
|
|
has granted you access to see their
|
|
<a href="{{.Link}}" class="has-text-private">private photos</a>!
|
|
</span>
|
|
{{else if eq .Type "new_photo"}}
|
|
<span class="icon">
|
|
{{if and $Body.Photo (eq $Body.Photo.Visibility "private")}}
|
|
<i class="fa fa-eye {{if $Body.Photo.Explicit}}has-text-danger{{else}}has-text-private{{end}}"></i>
|
|
{{else if and $Body.Photo (eq $Body.Photo.Visibility "circle")}}
|
|
<img src="/static/img/circle-16.png">
|
|
{{else}}
|
|
<i class="fa fa-image {{if $Body.Photo.Explicit}}has-text-danger{{else}}has-text-link{{end}}"></i>
|
|
{{end}}
|
|
</span>
|
|
<span>
|
|
<a href="/u/{{.AboutUser.Username}}"><strong>{{.AboutUser.Username}}</strong></a>
|
|
has uploaded a new
|
|
{{if and $Body.Photo (eq $Body.Photo.Visibility "private")}}
|
|
<span class="has-text-private">private photo!</span>
|
|
{{else}}
|
|
photo!
|
|
{{end}}
|
|
</span>
|
|
{{else if eq .Type "cert_approved"}}
|
|
<span class="icon"><i class="fa fa-certificate has-text-success"></i></span>
|
|
<span>
|
|
Your <strong>certification photo</strong> was approved!
|
|
</span>
|
|
{{else if eq .Type "cert_secondary"}}
|
|
<span class="icon"><i class="fa fa-certificate has-text-warning"></i></span>
|
|
<span>
|
|
About your <strong>certification photo:</strong>
|
|
</span>
|
|
{{else if eq .Type "cert_rejected"}}
|
|
<span class="icon"><i class="fa fa-certificate has-text-danger"></i></span>
|
|
<span>
|
|
Your <strong>certification photo</strong> was rejected!
|
|
</span>
|
|
{{else if eq .Type "inner_circle"}}
|
|
<span class="icon"><img src="/static/img/circle-16.png"></span>
|
|
<span>
|
|
You have been added to the {{PrettyCircle}} of nonshy.
|
|
</span>
|
|
|
|
<div class="block content mt-2">
|
|
<a href="/inner-circle">Click to learn more</a> about the inner circle.
|
|
</div>
|
|
{{else}}
|
|
{{.AboutUser.Username}} {{.Type}} {{.TableName}} {{.TableID}}
|
|
{{end}}
|
|
</div>
|
|
|
|
<!-- Attached message? -->
|
|
{{if .Message}}
|
|
<div class="block content mb-1">
|
|
<blockquote class="p-2 pl-4">{{ToMarkdown (TrimEllipses .Message 256)}}</blockquote>
|
|
</div>
|
|
{{end}}
|
|
|
|
<!-- Attached forum thread? -->
|
|
{{if $Body.Thread}}
|
|
<div>
|
|
On thread: <a href="{{.Link}}">{{$Body.Thread.Title}}</a>
|
|
</div>
|
|
{{end}}
|
|
|
|
<!-- Photo caption? -->
|
|
{{if $Body.Photo}}
|
|
<div class="block">
|
|
<!-- If it's a comment, have a link to view it -->
|
|
{{if eq .Type "comment"}}
|
|
<div class="is-size-7 pt-1">
|
|
<span class="icon"><i class="fa fa-arrow-right"></i></span>
|
|
<a href="{{.Link}}">See all comments</a>
|
|
</div>
|
|
{{else}}
|
|
<em>{{or $Body.Photo.Caption "No caption."}}</em>
|
|
{{end}}
|
|
|
|
<!-- Admin action: mark this pic explicit? -->
|
|
{{if and ($Root.CurrentUser.IsAdmin) (not $Body.Photo.Explicit)}}
|
|
<div class="mt-2">
|
|
<a href="/admin/photo/mark-explicit?photo_id={{$Body.Photo.ID}}&next={{$Root.Request.URL}}"
|
|
class="has-text-danger is-size-7"
|
|
onclick="return confirm('Do you want to mark this photo as Explicit?')">
|
|
<i class="fa fa-peace mr-1"></i>
|
|
Mark photo as Explicit
|
|
</a>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
|
|
<hr class="has-background-light mb-1">
|
|
<small title="{{.CreatedAt.Format "2006-01-02 15:04:05"}}">
|
|
{{SincePrettyCoarse .CreatedAt}} ago.
|
|
|
|
<!-- Delete button for just this notification -->
|
|
<button type="button"
|
|
class="button is-danger is-light is-small nonshy-notif-delete-button"
|
|
data-notification-id="{{.ID}}"
|
|
title="Remove this notification from your feed">
|
|
<i class="fa fa-xmark mr-1"></i> Clear
|
|
</button>
|
|
</small>
|
|
</div>
|
|
|
|
<!-- Attached photo? -->
|
|
{{if $Body.PhotoID}}
|
|
<div class="column is-one-quarter is-clipped">
|
|
<!-- GIF video? -->
|
|
{{if HasSuffix $Body.Photo.Filename ".mp4"}}
|
|
<video loop controls controlsList="nodownload" playsinline
|
|
{{if $Body.Photo.AltText}}title="{{$Body.Photo.AltText}}"{{end}}
|
|
{{if BlurExplicit $Body.Photo}}class="blurred-explicit"
|
|
{{else if (not (eq ($Root.CurrentUser.GetProfileField "autoplay_gif") "false"))}}autoplay
|
|
{{end}}>
|
|
<source src="{{PhotoURL $Body.Photo.Filename}}" type="video/mp4">
|
|
</video>
|
|
<div>
|
|
<a href="/photo/view?id={{$Body.Photo.ID}}" class="is-size-7">
|
|
<i class="fa fa-arrow-right"></i> View GIF
|
|
</a>
|
|
</div>
|
|
{{else}}
|
|
<a href="/photo/view?id={{$Body.Photo.ID}}">
|
|
<img src="{{PhotoURL $Body.Photo.Filename}}" loading="lazy"
|
|
{{if BlurExplicit $Body.Photo}} class="blurred-explicit"{{end}}
|
|
{{if $Body.Photo.AltText}}title="{{$Body.Photo.AltText}}" alt="{{$Body.Photo.AltText}}"{{end}}>
|
|
</a>
|
|
{{end}}
|
|
|
|
{{if $Body.Photo.Caption}}
|
|
<small>{{$Body.Photo.Caption}}</small>
|
|
{{else}}
|
|
<small><em>No caption.</em></small>
|
|
{{end}}
|
|
|
|
<!-- Like button for the photo right here -->
|
|
{{if ne $Body.Photo.UserID $Root.CurrentUser.ID}}
|
|
<div class="mt-1">
|
|
{{$Like := $Root.PhotoLikeMap.Get $Body.PhotoID}}
|
|
<button type="button" class="button is-small nonshy-like-button"
|
|
data-table-name="photos" data-table-id="{{$Body.PhotoID}}"
|
|
title="Like">
|
|
<span class="icon{{if $Like.UserLikes}} has-text-danger{{end}}"><i class="fa fa-heart"></i></span>
|
|
<span class="nonshy-likes">
|
|
Like
|
|
{{if gt $Like.Count 0}}
|
|
({{$Like.Count}})
|
|
{{end}}
|
|
</span>
|
|
</button>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
|
|
</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
|
|
{{if .Pager.HasNext}}
|
|
<div class="has-text-centered">
|
|
<a href="{{.Request.URL.Path}}?{{QueryPlus "page" .Pager.Next}}" class="button">View older notifications</a>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="text/javascript">
|
|
// Notifications helper.
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
let busy = false;
|
|
|
|
// For delete buttons: if they click thru the first confirm, do not ask every single time
|
|
// for the rest of the current page load.
|
|
let dontAskAgain = false;
|
|
|
|
// Bind to the notification table rows.
|
|
(document.querySelectorAll(".nonshy-notification-row") || []).forEach(node => {
|
|
let $newBadge = node.querySelector(".nonshy-notification-new"),
|
|
$deleteButton = node.querySelector(".nonshy-notif-delete-button"),
|
|
ID = node.dataset.notificationId;
|
|
|
|
// Delete buttons for individual notifications.
|
|
$deleteButton.addEventListener("click", (e) => {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
if (!dontAskAgain) {
|
|
if (!window.confirm(
|
|
"Do you want to DELETE this notification?\n\nNote: If you click Ok, you will not be asked "+
|
|
"the next time you want to delete another notification until your next page reload."
|
|
)) {
|
|
return;
|
|
}
|
|
dontAskAgain = true;
|
|
}
|
|
|
|
busy = true;
|
|
return fetch("/v1/notifications/delete", {
|
|
method: "POST",
|
|
mode: "same-origin",
|
|
cache: "no-cache",
|
|
credentials: "same-origin",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
"id": parseInt(ID),
|
|
}),
|
|
})
|
|
.then((response) => response.json())
|
|
.then((data) => {
|
|
console.log(data);
|
|
|
|
// Hide the notification row immediately.
|
|
node.style.display = 'none';
|
|
}).catch(resp => {
|
|
window.alert(resp);
|
|
}).finally(() => {
|
|
busy = false;
|
|
});
|
|
});
|
|
|
|
// If the notification doesn't have a "NEW!" badge, no action needed.
|
|
if ($newBadge === null) return;
|
|
|
|
// Collect any hyperlinks in this row.
|
|
let links = Array.from(node.querySelectorAll("a"));
|
|
links.push(node);
|
|
|
|
// Apply a "click" handler to the notification row as a whole, and to all of the hyperlinks in it.
|
|
// For the hyperlinks: prevent the browser following the link UNTIL the successful ajax request to
|
|
// mark the notification "read" has run.
|
|
links.forEach(link => {
|
|
link.addEventListener("click", (e) => {
|
|
if (busy) return;
|
|
|
|
// In case it's a hyperlink, grab the href.
|
|
let href = link.attributes.href;
|
|
if (href !== undefined) {
|
|
e.preventDefault();
|
|
href = href.textContent;
|
|
}
|
|
|
|
$newBadge.style.display = "none";
|
|
|
|
busy = true;
|
|
return fetch("/v1/notifications/read", {
|
|
method: "POST",
|
|
mode: "same-origin",
|
|
cache: "no-cache",
|
|
credentials: "same-origin",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
"id": parseInt(ID),
|
|
}),
|
|
})
|
|
.then((response) => response.json())
|
|
.then((data) => {
|
|
console.log(data);
|
|
}).catch(resp => {
|
|
window.alert(resp);
|
|
}).finally(() => {
|
|
busy = false;
|
|
if (href !== undefined) {
|
|
window.location.href = href;
|
|
}
|
|
});
|
|
})
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
{{end}}
|