Compare commits
2 Commits
4806b0aa41
...
83ed793e39
Author | SHA1 | Date |
---|---|---|
|
83ed793e39 | |
|
3f55b90ab8 |
|
@ -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 {
|
||||||
|
|
|
@ -85,18 +85,22 @@
|
||||||
<Tooltip v-if="me">
|
<Tooltip v-if="me">
|
||||||
<div
|
<div
|
||||||
class="header-button header-notifications"
|
class="header-button header-notifications"
|
||||||
:class="{ unseen: unseenNotifications.length > 0 }"
|
:class="{ unseen: unseenNotificationsCount > 0 }"
|
||||||
>
|
>
|
||||||
<Icon icon="bell2" />
|
<Icon icon="bell2" />
|
||||||
|
|
||||||
<span
|
<span
|
||||||
v-if="unseenNotifications.length > 0"
|
v-if="unseenNotificationsCount > 0"
|
||||||
class="notifications-count"
|
class="notifications-count"
|
||||||
>{{ unseenNotifications.length }}</span>
|
>{{ unseenNotificationsCount }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template v-slot:tooltip>
|
<template v-slot:tooltip>
|
||||||
<Notifications />
|
<Notifications
|
||||||
|
:notifications="notifications"
|
||||||
|
:unseen-count="unseenNotificationsCount"
|
||||||
|
@check="fetchNotifications"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
|
@ -115,8 +119,6 @@
|
||||||
</template>
|
</template>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Search class="search-full" />
|
|
||||||
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
class="search-compact"
|
class="search-compact"
|
||||||
:open="searching"
|
:open="searching"
|
||||||
|
@ -139,6 +141,8 @@
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
|
<Search class="search-full" />
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
|
@ -154,12 +158,11 @@ function me() {
|
||||||
return this.$store.state.auth.user;
|
return this.$store.state.auth.user;
|
||||||
}
|
}
|
||||||
|
|
||||||
function notifications() {
|
async function fetchNotifications() {
|
||||||
return this.$store.state.ui.notifications;
|
const { notifications, unseenCount } = await this.$store.dispatch('fetchNotifications');
|
||||||
}
|
|
||||||
|
|
||||||
function unseenNotifications() {
|
this.notifications = notifications;
|
||||||
return this.$store.state.ui.notifications.filter(notification => !notification.seen);
|
this.unseenNotificationsCount = unseenCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -174,12 +177,19 @@ export default {
|
||||||
logo,
|
logo,
|
||||||
searching: false,
|
searching: false,
|
||||||
showFilters: false,
|
showFilters: false,
|
||||||
|
notifications: [],
|
||||||
|
unseenNotificationsCount: 0,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
me,
|
me,
|
||||||
notifications,
|
},
|
||||||
unseenNotifications,
|
watch: {
|
||||||
|
me: fetchNotifications,
|
||||||
|
},
|
||||||
|
mounted: fetchNotifications,
|
||||||
|
methods: {
|
||||||
|
fetchNotifications,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -315,12 +325,12 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-account {
|
.header-account {
|
||||||
padding: 1rem 1rem 1rem .75rem;
|
padding: 1rem 1.25rem 1rem .75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-notifications {
|
.header-notifications {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 1rem .75rem 1rem 1rem;
|
padding: 1rem .75rem;
|
||||||
|
|
||||||
&.unseen .icon {
|
&.unseen .icon {
|
||||||
fill: var(--primary);
|
fill: var(--primary);
|
||||||
|
@ -334,7 +344,7 @@ export default {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: .3rem;
|
bottom: .3rem;
|
||||||
left: .1rem;
|
left: 0;
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
font-size: .6rem;
|
font-size: .6rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div class="notifications">
|
||||||
class="notifications"
|
|
||||||
>
|
|
||||||
<div class="notifications-header">
|
<div class="notifications-header">
|
||||||
<h4 class="notifications-title">Notifications</h4>
|
<h4 class="notifications-title">Notifications</h4>
|
||||||
|
|
||||||
<div class="notifications-actions">
|
<div class="notifications-actions">
|
||||||
<Icon
|
<Icon
|
||||||
v-if="unseenNotifications.length > 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"
|
||||||
/>
|
/>
|
||||||
|
@ -40,7 +39,7 @@
|
||||||
:key="`notification-${notification.id}`"
|
:key="`notification-${notification.id}`"
|
||||||
:class="{ unseen: !notification.seen }"
|
:class="{ unseen: !notification.seen }"
|
||||||
class="notification"
|
class="notification"
|
||||||
@click="checkNotification(notification.id)"
|
@click="checkNotification(notification.id, true)"
|
||||||
>
|
>
|
||||||
<router-link
|
<router-link
|
||||||
:to="`/scene/${notification.scene.id}/${notification.scene.slug}`"
|
:to="`/scene/${notification.scene.id}/${notification.scene.slug}`"
|
||||||
|
@ -100,56 +99,67 @@
|
||||||
v-tooltip="'Mark as seen'"
|
v-tooltip="'Mark as seen'"
|
||||||
icon="checkmark"
|
icon="checkmark"
|
||||||
class="notification-check"
|
class="notification-check"
|
||||||
@click.prevent="checkNotification(notification.id)"
|
@click.prevent.stop="checkNotification(notification.id)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Icon
|
<Icon
|
||||||
v-if="notification.alert"
|
v-if="notification.alert"
|
||||||
v-tooltip="`You set an alert for <strong>${notification.alert.tags.map(tag => tag.name).join(', ') || 'all'}</strong> scenes with <strong>${notification.alert.actors.map(actor => actor.name).join(', ') || 'any actor'}</strong> for <strong>${notification.alert.entity?.name || 'any channel'}</strong>`"
|
v-tooltip="`You set an alert for <strong>${notification.alert.tags.map(tag => tag.name).join(', ') || 'all'}</strong> scenes with <strong>${notification.alert.actors.map(actor => actor.name).join(', ') || 'any actor'}</strong> for <strong>${notification.alert.entity?.name || 'any channel'}</strong>`"
|
||||||
icon="question5"
|
icon="question5"
|
||||||
@click.prevent
|
@click.prevent.stop
|
||||||
/>
|
/>
|
||||||
</router-link>
|
</router-link>
|
||||||
</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 unseenNotifications() {
|
|
||||||
return this.notifications.filter(notification => !notification.seen);
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
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) {
|
||||||
|
this.events.emit('blur');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
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,
|
|
||||||
unseenNotifications,
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
checkNotifications,
|
checkNotifications,
|
||||||
checkNotification,
|
checkNotification,
|
||||||
|
@ -160,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 {
|
||||||
|
@ -170,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;
|
||||||
}
|
}
|
||||||
|
@ -191,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,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 {
|
||||||
|
@ -213,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;
|
||||||
}
|
}
|
||||||
|
@ -224,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 {
|
||||||
|
@ -305,8 +328,22 @@ 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;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
object-position: center;
|
object-position: center;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ export default {
|
||||||
query: this.$route.query ? this.$route.query.q : null,
|
query: this.$route.query ? this.$route.query.q : null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
emits: ['search'],
|
||||||
watch: {
|
watch: {
|
||||||
$route: route,
|
$route: route,
|
||||||
searching,
|
searching,
|
||||||
|
@ -71,8 +72,8 @@ export default {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
padding: 0 1rem 0 0;
|
|
||||||
border-left: solid 1px var(--shadow-hint);
|
border-left: solid 1px var(--shadow-hint);
|
||||||
|
margin: 0 .25rem 0 0;
|
||||||
|
|
||||||
&.compact {
|
&.compact {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -92,7 +93,7 @@ export default {
|
||||||
.search-input {
|
.search-input {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: .5rem 0 .5rem .5rem;
|
padding: .5rem 0 .5rem .75rem;
|
||||||
border: none;
|
border: none;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
|
@ -119,14 +120,20 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus::placeholder {
|
&:focus {
|
||||||
color: var(--shadow-weak);
|
&::placeholder {
|
||||||
|
color: var(--shadow-weak);
|
||||||
|
}
|
||||||
|
|
||||||
|
& + .search-button:not(:hover) .icon {
|
||||||
|
fill: var(--shadow);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-button {
|
.search-button {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 0 1rem;
|
padding: 0 1.25rem 0 1rem;
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
margin: .3rem 0 0 0;
|
margin: .3rem 0 0 0;
|
||||||
|
@ -140,7 +147,7 @@ export default {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
fill: var(--shadow);
|
fill: var(--primary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
|
@ -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"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { get, post, del } from '../api';
|
import { get, post, del } from '../api';
|
||||||
|
|
||||||
function initAuthActions(_store, _router) {
|
function initAuthActions(store, _router) {
|
||||||
async function fetchMe({ commit }) {
|
async function fetchMe({ commit }) {
|
||||||
try {
|
try {
|
||||||
const user = await get('/session');
|
const user = await get('/session');
|
||||||
|
@ -18,6 +18,7 @@ function initAuthActions(_store, _router) {
|
||||||
const user = await post('/session', credentials);
|
const user = await post('/session', credentials);
|
||||||
|
|
||||||
commit('setUser', user);
|
commit('setUser', user);
|
||||||
|
await store.dispatch('fetchNotifications');
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -29,63 +29,79 @@ 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 [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const { notifications } = await graphql(`
|
const { notifications, unseenNotifications } = await graphql(`
|
||||||
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(
|
||||||
|
filter: { seen: { equalTo: false } }
|
||||||
|
) {
|
||||||
|
totalCount
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`, {
|
`, {
|
||||||
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);
|
return {
|
||||||
return curatedNotifications;
|
notifications: curatedNotifications,
|
||||||
|
totalCount: notifications.totalCount,
|
||||||
|
unseenCount: unseenNotifications.totalCount,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkNotification(context, notificationId) {
|
async function checkNotification(context, notificationId) {
|
||||||
|
@ -197,9 +213,11 @@ 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)) || [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
function setNotifications(state, notifications) {
|
|
||||||
state.notifications = notifications;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setTagFilter(state, tagFilter) {
|
function setTagFilter(state, tagFilter) {
|
||||||
state.tagFilter = tagFilter;
|
state.tagFilter = tagFilter;
|
||||||
}
|
}
|
||||||
|
@ -23,7 +19,6 @@ function setTheme(state, theme) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
setNotifications,
|
|
||||||
setTagFilter,
|
setTagFilter,
|
||||||
setRange,
|
setRange,
|
||||||
setBatch,
|
setBatch,
|
||||||
|
|
|
@ -11,5 +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: [],
|
|
||||||
};
|
};
|
||||||
|
|
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 |
|
@ -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',
|
||||||
},
|
},
|
||||||
|
|
|
@ -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'],
|
||||||
|
|
|
@ -51,11 +51,11 @@ async function removeAlert(alertId) {
|
||||||
|
|
||||||
async function notify(scenes) {
|
async function notify(scenes) {
|
||||||
const releases = await knex.raw(`
|
const releases = await knex.raw(`
|
||||||
SELECT alerts.id as alert_id, alerts.notify, alerts.email, releases.id as scene_id, users.id as user_id
|
SELECT alerts.id as alert_id, alerts.notify, alerts.email, releases.id as scene_id, users.id as user_id, COALESCE(json_agg(alerts_stashes.stash_id) FILTER (WHERE alerts_stashes.stash_id IS NOT NULL), '[]') as stashes
|
||||||
FROM releases
|
FROM releases
|
||||||
CROSS JOIN alerts
|
CROSS JOIN alerts
|
||||||
LEFT JOIN users ON users.id = alerts.user_id
|
LEFT JOIN users ON users.id = alerts.user_id
|
||||||
LEFT JOIN releases_tags ON releases_tags.release_id = releases.id
|
LEFT JOIN alerts_stashes ON alerts_stashes.alert_id = alerts.id
|
||||||
/* match updated IDs from input */
|
/* match updated IDs from input */
|
||||||
WHERE (releases.id = ANY(:sceneIds))
|
WHERE (releases.id = ANY(:sceneIds))
|
||||||
/* match tags */
|
/* match tags */
|
||||||
|
@ -111,15 +111,26 @@ async function notify(scenes) {
|
||||||
sceneIds: scenes.map(scene => scene.id),
|
sceneIds: scenes.map(scene => scene.id),
|
||||||
});
|
});
|
||||||
|
|
||||||
const notifications = releases.rows.filter(alert => alert.notify);
|
const notifications = releases.rows
|
||||||
|
.filter(alert => alert.notify)
|
||||||
await knex('notifications')
|
.map(notification => ({
|
||||||
.insert(notifications.map(notification => ({
|
|
||||||
user_id: notification.user_id,
|
user_id: notification.user_id,
|
||||||
alert_id: notification.alert_id,
|
alert_id: notification.alert_id,
|
||||||
scene_id: notification.scene_id,
|
scene_id: notification.scene_id,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const stashes = releases.rows
|
||||||
|
.filter(release => release.stashes.length > 0)
|
||||||
|
.flatMap(release => release.stashes.map(stash => ({
|
||||||
|
scene_id: release.scene_id,
|
||||||
|
stash_id: stash,
|
||||||
})));
|
})));
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
knex('notifications').insert(notifications),
|
||||||
|
knex('stashes_scenes').insert(stashes),
|
||||||
|
]);
|
||||||
|
|
||||||
return releases.rows;
|
return releases.rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,8 +144,6 @@ async function updateNotification(notificationId, notification, sessionUser) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateNotifications(notification, sessionUser) {
|
async function updateNotifications(notification, sessionUser) {
|
||||||
console.log(notification, sessionUser.id);
|
|
||||||
|
|
||||||
await knex('notifications')
|
await knex('notifications')
|
||||||
.where('user_id', sessionUser.id)
|
.where('user_id', sessionUser.id)
|
||||||
.update({
|
.update({
|
||||||
|
|
Loading…
Reference in New Issue