Added dedicated notifications page.

This commit is contained in:
DebaucheryLibrarian 2021-05-09 00:23:10 +02:00
parent 3f55b90ab8
commit 83ed793e39
17 changed files with 220 additions and 77 deletions

View File

@ -137,7 +137,7 @@ async function fetchEntity(scroll = true) {
this.pageTitle = entity.name; this.pageTitle = entity.name;
if (scroll) { if (scroll && this.$refs.filter?.$el) {
this.$refs.filter.$el.scrollIntoView(); this.$refs.filter.$el.scrollIntoView();
} }
} }
@ -146,9 +146,11 @@ async function mounted() {
await this.fetchEntity(); await this.fetchEntity();
} }
async function route() { async function route(to) {
await this.fetchEntity(); if (to.name === 'channel' || to.name === 'network' || to.name === 'studio') {
this.expanded = false; await this.fetchEntity();
this.expanded = false;
}
} }
export default { export default {

View File

@ -96,7 +96,11 @@
</div> </div>
<template v-slot:tooltip> <template v-slot:tooltip>
<Notifications /> <Notifications
:notifications="notifications"
:unseen-count="unseenNotificationsCount"
@check="fetchNotifications"
/>
</template> </template>
</Tooltip> </Tooltip>
@ -154,8 +158,11 @@ function me() {
return this.$store.state.auth.user; return this.$store.state.auth.user;
} }
function unseenNotificationsCount() { async function fetchNotifications() {
return this.$store.state.ui.unseenNotificationsCount; const { notifications, unseenCount } = await this.$store.dispatch('fetchNotifications');
this.notifications = notifications;
this.unseenNotificationsCount = unseenCount;
} }
export default { export default {
@ -170,11 +177,19 @@ export default {
logo, logo,
searching: false, searching: false,
showFilters: false, showFilters: false,
notifications: [],
unseenNotificationsCount: 0,
}; };
}, },
computed: { computed: {
me, me,
unseenNotificationsCount, },
watch: {
me: fetchNotifications,
},
mounted: fetchNotifications,
methods: {
fetchNotifications,
}, },
}; };
</script> </script>

View File

@ -5,13 +5,14 @@
<div class="notifications-actions"> <div class="notifications-actions">
<Icon <Icon
v-if="unseenNotificationsCount > 0" v-if="unseenCount > 0"
v-tooltip="'Mark all as seen'" v-tooltip="'Mark all as seen'"
icon="checkmark" icon="checkmark"
@click="checkNotifications" @click="checkNotifications"
/> />
<Icon <Icon
v-tooltip="'Add alert'"
icon="plus3" icon="plus3"
@click="showAddAlert = true" @click="showAddAlert = true"
/> />
@ -111,28 +112,29 @@
</li> </li>
</ul> </ul>
</div> </div>
<div @click="$emit('blur')">
<router-link
to="/notifications"
class="notification-link notification-more"
>See all</router-link>
</div>
</div> </div>
</template> </template>
<script> <script>
import AddAlert from '../alerts/add.vue'; import AddAlert from '../alerts/add.vue';
function notifications() {
return this.$store.state.ui.notifications;
}
function unseenNotificationsCount() {
return this.$store.state.ui.unseenNotificationsCount;
}
async function checkNotifications() { async function checkNotifications() {
await this.$store.dispatch('checkNotifications'); await this.$store.dispatch('checkNotifications');
await this.$store.dispatch('fetchNotifications');
this.$emit('check');
} }
async function checkNotification(notificationId, blur) { async function checkNotification(notificationId, blur) {
await this.$store.dispatch('checkNotification', notificationId); await this.$store.dispatch('checkNotification', notificationId);
await this.$store.dispatch('fetchNotifications');
this.$emit('check');
if (blur) { if (blur) {
this.events.emit('blur'); this.events.emit('blur');
@ -143,15 +145,21 @@ export default {
components: { components: {
AddAlert, AddAlert,
}, },
props: {
notifications: {
type: Array,
default: () => [],
},
unseenCount: {
type: Number,
default: 0,
},
},
data() { data() {
return { return {
showAddAlert: false, showAddAlert: false,
}; };
}, },
computed: {
notifications,
unseenNotificationsCount,
},
methods: { methods: {
checkNotifications, checkNotifications,
checkNotification, checkNotification,
@ -162,6 +170,9 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.notifications { .notifications {
width: 30rem; width: 30rem;
max-height: calc(100vh - 5rem);
display: flex;
flex-direction: column;
} }
.notifications-header { .notifications-header {
@ -172,11 +183,15 @@ export default {
padding: .5rem; padding: .5rem;
fill: var(--shadow); fill: var(--shadow);
&:last-child { &:first-child {
padding: .5rem 1rem .5rem .5rem; padding: .5rem .5rem .5rem 1.5rem;
} }
:hover { &:last-child {
padding: .5rem 1.5rem .5rem .5rem;
}
&:hover {
fill: var(--primary); fill: var(--primary);
cursor: pointer; cursor: pointer;
} }
@ -193,6 +208,8 @@ export default {
} }
.notifications-body { .notifications-body {
flex-grow: 1;
overflow-y: auto;
box-shadow: 0 0 3px var(--shadow-weak); box-shadow: 0 0 3px var(--shadow-weak);
} }
@ -204,7 +221,6 @@ export default {
.notification { .notification {
display: block; display: block;
border-right: solid .5rem var(--shadow-touch); border-right: solid .5rem var(--shadow-touch);
margin: 0 0 -1px 0;
color: var(--text); color: var(--text);
&.unseen { &.unseen {
@ -215,6 +231,10 @@ export default {
padding: 1.3rem .5rem; padding: 1.3rem .5rem;
fill: var(--shadow-weak); fill: var(--shadow-weak);
&.notification-check {
padding: 1.3rem .5rem 1.3rem 1rem;
}
&:last-child { &:last-child {
padding: 1.3rem 1rem 1.3rem .5rem; padding: 1.3rem 1rem 1.3rem .5rem;
} }
@ -226,6 +246,7 @@ export default {
&:not(:last-child) { &:not(:last-child) {
border-bottom: solid 1px var(--shadow-hint); border-bottom: solid 1px var(--shadow-hint);
margin: 0 0 -1px 0;
} }
&:hover { &:hover {
@ -307,6 +328,19 @@ export default {
font-weight: bold; font-weight: bold;
} }
.notification-more {
display: block;
padding: .5rem 1rem;
color: var(--shadow);
text-align: center;
font-size: .9rem;
font-weight: bold;
&:hover {
color: var(--primary);
}
}
.poster { .poster {
width: 6rem; width: 6rem;
height: 3.6rem; height: 3.6rem;

View File

@ -0,0 +1,76 @@
<template>
<div
ref="page"
class="notifications-container"
>
<h1 class="heading">Notifications</h1>
<ul class="notifications nolist">
<li
v-for="notification in notifications"
:key="notification.id"
>
<SceneTile :release="notification.scene" />
</li>
</ul>
<Pagination
:items-total="totalCount"
:items-per-page="10"
/>
</div>
</template>
<script>
import Pagination from '../pagination/pagination.vue';
import SceneTile from '../releases/scene-tile.vue';
async function fetchNotifications() {
const { notifications, totalCount, unseenCount } = await this.$store.dispatch('fetchNotifications', {
page: this.$route.params.pageNumber,
limit: this.limit,
});
this.notifications = notifications;
this.unseenNotificationsCount = unseenCount;
this.totalCount = totalCount;
this.$emit('scroll');
}
export default {
components: {
Pagination,
SceneTile,
},
data() {
return {
notifications: [],
limit: 10,
totalCount: 0,
unseenNotificationsCount: 0,
};
},
emits: ['scroll'],
watch: {
$route: fetchNotifications,
},
mounted: fetchNotifications,
};
</script>
<style lang="scss" scoped>
.notifications-container {
padding: 1rem;
}
.notifications {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(22rem, 1fr));
grid-gap: .5rem;
}
.pagination {
margin: 1rem 0 0 0;
}
</style>

View File

@ -22,6 +22,8 @@
:src="getPath(release.poster, 'thumbnail')" :src="getPath(release.poster, 'thumbnail')"
:style="{ 'background-image': getBgPath(release.poster, 'lazy') }" :style="{ 'background-image': getBgPath(release.poster, 'lazy') }"
:alt="release.title" :alt="release.title"
:width="release.poster.thumbnailWidth"
:height="release.poster.thumbnailHeight"
class="thumbnail" class="thumbnail"
loading="lazy" loading="lazy"
> >
@ -31,6 +33,8 @@
:src="getPath(release.photos[0], 'thumbnail')" :src="getPath(release.photos[0], 'thumbnail')"
:style="{ 'background-image': getBgPath(release.photos[0], 'lazy') } " :style="{ 'background-image': getBgPath(release.photos[0], 'lazy') } "
:alt="release.title" :alt="release.title"
:width="release.photos[0].thumbnailWidth"
:height="release.photos[0].thumbnailHeight"
class="thumbnail" class="thumbnail"
loading="lazy" loading="lazy"
> >

View File

@ -10,6 +10,7 @@ import Networks from '../components/networks/networks.vue';
import Actor from '../components/actors/actor.vue'; import Actor from '../components/actors/actor.vue';
import Actors from '../components/actors/actors.vue'; import Actors from '../components/actors/actors.vue';
import Movies from '../components/releases/movies.vue'; import Movies from '../components/releases/movies.vue';
import Notifications from '../components/notifications/notifications.vue';
import Tag from '../components/tags/tag.vue'; import Tag from '../components/tags/tag.vue';
import Tags from '../components/tags/tags.vue'; import Tags from '../components/tags/tags.vue';
import Stash from '../components/stashes/stash.vue'; import Stash from '../components/stashes/stash.vue';
@ -202,6 +203,20 @@ const routes = [
component: Tags, component: Tags,
name: 'tags', name: 'tags',
}, },
{
path: '/notifications',
redirect: {
name: 'notifications',
params: {
pageNumber: 1,
},
},
},
{
path: '/notifications/:pageNumber',
component: Notifications,
name: 'notifications',
},
{ {
path: '/stash/:stashId/:stashSlug?', path: '/stash/:stashId/:stashSlug?',
component: Stash, component: Stash,

View File

@ -29,7 +29,7 @@ function initUiActions(store, _router) {
localStorage.setItem('sfw', sfw); localStorage.setItem('sfw', sfw);
} }
async function fetchNotifications({ commit }) { async function fetchNotifications(_context, { page = 1, limit = 10 } = {}) {
if (!store.state.auth.user) { if (!store.state.auth.user) {
return []; return [];
} }
@ -38,44 +38,50 @@ function initUiActions(store, _router) {
query Notifications( query Notifications(
$hasAuth: Boolean! $hasAuth: Boolean!
$userId: Int $userId: Int
$limit: Int = 10
$offset: Int = 0
) { ) {
notifications( notifications: notificationsConnection(
first: 10 first: $limit
offset: $offset
orderBy: CREATED_AT_DESC orderBy: CREATED_AT_DESC
) { ) {
id nodes {
sceneId id
userId sceneId
seen userId
createdAt seen
scene { createdAt
${releaseFields} scene {
} ${releaseFields}
alert {
tags: alertsTags {
tag {
id
name
slug
}
} }
actors: alertsActors { alert {
actor { tags: alertsTags {
id tag {
name id
slug name
slug
}
} }
} actors: alertsActors {
entity: alertsEntityByAlertId { actor {
entity { id
id name
name slug
slug }
independent }
entity: alertsEntityByAlertId {
entity {
id
name
slug
independent
}
} }
} }
} }
} totalCount
}
unseenNotifications: notificationsConnection( unseenNotifications: notificationsConnection(
filter: { seen: { equalTo: false } } filter: { seen: { equalTo: false } }
) { ) {
@ -85,15 +91,15 @@ function initUiActions(store, _router) {
`, { `, {
hasAuth: !!store.state.auth.user, hasAuth: !!store.state.auth.user,
userId: store.state.auth.user?.id, userId: store.state.auth.user?.id,
limit,
offset: (page - 1) * limit,
}); });
const curatedNotifications = notifications.map(notification => curateNotification(notification)); const curatedNotifications = notifications.nodes.map(notification => curateNotification(notification));
commit('setNotifications', curatedNotifications);
commit('setUnseenNotificationsCount', unseenNotifications.totalCount);
return { return {
notifications: curatedNotifications, notifications: curatedNotifications,
totalCount: notifications.totalCount,
unseenCount: unseenNotifications.totalCount, unseenCount: unseenNotifications.totalCount,
}; };
} }
@ -207,6 +213,8 @@ function initUiActions(store, _router) {
userId: store.state.auth.user?.id, userId: store.state.auth.user?.id,
}); });
console.log(res.results);
return { return {
releases: res?.results.map(result => curateRelease(result.release)) || [], releases: res?.results.map(result => curateRelease(result.release)) || [],
actors: res?.actors.map(actor => curateActor(actor)) || [], actors: res?.actors.map(actor => curateActor(actor)) || [],

View File

@ -1,11 +1,3 @@
function setNotifications(state, notifications) {
state.notifications = notifications;
}
function setUnseenNotificationsCount(state, count) {
state.unseenNotificationsCount = count;
}
function setTagFilter(state, tagFilter) { function setTagFilter(state, tagFilter) {
state.tagFilter = tagFilter; state.tagFilter = tagFilter;
} }
@ -27,8 +19,6 @@ function setTheme(state, theme) {
} }
export default { export default {
setNotifications,
setUnseenNotificationsCount,
setTagFilter, setTagFilter,
setRange, setRange,
setBatch, setBatch,

View File

@ -11,6 +11,4 @@ export default {
batch: storedBatch || 'all', batch: storedBatch || 'all',
sfw: storedSfw === 'true' || false, sfw: storedSfw === 'true' || false,
theme: storedTheme || deviceTheme, theme: storedTheme || deviceTheme,
notifications: [],
unseenNotificationsCount: 0,
}; };

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -2989,7 +2989,7 @@ const sites = [
{ {
name: 'Black Ambush', name: 'Black Ambush',
slug: 'blackambush', slug: 'blackambush',
alias: ['interracial', 'bbc'], tags: ['bbc'],
url: 'https://blackambush.com', url: 'https://blackambush.com',
parent: 'exploitedx', parent: 'exploitedx',
}, },

View File

@ -763,8 +763,9 @@ const tagMedia = [
['dv-tp', 0, 'Luna Rival in SZ1490'], ['dv-tp', 0, 'Luna Rival in SZ1490'],
['facefucking', 5, 'Mia Moore B', 'throated'], ['facefucking', 5, 'Mia Moore B', 'throated'],
['facefucking', 6, 'Halle Hayes in "Towering Temptress"', '5kporn'], ['facefucking', 6, 'Halle Hayes in "Towering Temptress"', '5kporn'],
['facefucking', 7, 'Anya Olsen and Audrey Snow in "Babysitter Busted Giving A BJ"', 'mommyblowsbest'], ['facefucking', 'adria_rae_throated', 'Adria Rae in "Adria Rae Sucks Cock All Day"', 'throated'],
['facefucking', 1, 'Paige Owens in "Dark Meat 12"', 'evilangel'], ['facefucking', 1, 'Paige Owens in "Dark Meat 12"', 'evilangel'],
['facefucking', 7, 'Anya Olsen and Audrey Snow in "Babysitter Busted Giving A BJ"', 'mommyblowsbest'],
['facefucking', 0, 'Ashly Anderson in "Rough Love"', 'hookuphotshot'], ['facefucking', 0, 'Ashly Anderson in "Rough Love"', 'hookuphotshot'],
['facefucking', 2, 'Jynx Maze', 'throated'], ['facefucking', 2, 'Jynx Maze', 'throated'],
['facefucking', 4, 'Brooklyn Gray in "Throats Fucks 6"', 'evilangel'], ['facefucking', 4, 'Brooklyn Gray in "Throats Fucks 6"', 'evilangel'],
@ -793,7 +794,7 @@ const tagMedia = [
['enhanced-boobs', '23d', 'Lulu Sex Bomb in "Tropical Touch"'], ['enhanced-boobs', '23d', 'Lulu Sex Bomb in "Tropical Touch"'],
['enhanced-boobs', 22, 'Sakura Sena'], ['enhanced-boobs', 22, 'Sakura Sena'],
['enhanced-boobs', 'mareeva_trudy_photodromm_1', 'Mareeva and Trudy', 'photodromm'], ['enhanced-boobs', 'mareeva_trudy_photodromm_1', 'Mareeva and Trudy', 'photodromm'],
['enhanced-boobs', 'lara_frost_legalporno', 'Lara Frost in NRX059', 'legalporno'], ['enhanced-boobs', 'lara_frost_handsonhardcore', 'Lara Frost in "Handyman & Hubby Try To Satisfy Horny Little Ukrainian Nympho"', 'handsonhardcore'],
['enhanced-boobs', 'shawna_lenee_inthecrack_3', 'Shawna Lenee', 'inthecrack'], ['enhanced-boobs', 'shawna_lenee_inthecrack_3', 'Shawna Lenee', 'inthecrack'],
['enhanced-boobs', 16, 'Marsha May in "Once You Go Black 7"', 'julesjordan'], ['enhanced-boobs', 16, 'Marsha May in "Once You Go Black 7"', 'julesjordan'],
['enhanced-boobs', 'azul_hermosa_pornstarslikeitbig', 'Azul Hermosa in "She Likes Rough Quickies"', 'pornstarslikeitbig'], ['enhanced-boobs', 'azul_hermosa_pornstarslikeitbig', 'Azul Hermosa in "She Likes Rough Quickies"', 'pornstarslikeitbig'],