read comment notification working
This commit is contained in:
parent
9222069ef5
commit
246d21f85a
17 changed files with 86 additions and 111 deletions
|
|
@ -40,6 +40,5 @@ fields:
|
||||||
disabled: true
|
disabled: true
|
||||||
date:
|
date:
|
||||||
type: hidden
|
type: hidden
|
||||||
isread:
|
readby:
|
||||||
type: toggle
|
type: users
|
||||||
disabled: true
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
title: Admin
|
title: Admin
|
||||||
description: Possède tous les droits et les accès, peut accéder à l’ensemble des Clients et des Projets et assigner des Projets à des Utilisateurs.
|
description: Possède tous les droits et les accès, peut accéder à l’ensemble des Clients et des Projets et assigner des Projets à des Utilisateurs.
|
||||||
home: /panel/pages/projects
|
home: /panel/pages/projects
|
||||||
|
|
||||||
fields:
|
|
||||||
notifications: fields/notifications
|
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,7 @@ permissions:
|
||||||
panel: false
|
panel: false
|
||||||
|
|
||||||
fields:
|
fields:
|
||||||
client:
|
|
||||||
type: pages
|
|
||||||
max: 1
|
|
||||||
query: page('clients').children
|
|
||||||
projects:
|
projects:
|
||||||
label: Projets
|
label: Projets
|
||||||
type: pages
|
type: pages
|
||||||
query: page('projects').children
|
query: page('projects').children
|
||||||
notifications: fields/notifications
|
|
||||||
|
|
|
||||||
|
|
@ -19,4 +19,3 @@ fields:
|
||||||
type: pages
|
type: pages
|
||||||
query: page('projects').children
|
query: page('projects').children
|
||||||
width: 3/4
|
width: 3/4
|
||||||
notifications: fields/notifications
|
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,10 @@ return function ($page, $kirby, $site) {
|
||||||
|
|
||||||
$userData = [
|
$userData = [
|
||||||
"role" => (string) $kirby->user()->role(),
|
"role" => (string) $kirby->user()->role(),
|
||||||
"uuid" => (string) $kirby->user()->uuid(),
|
"uuid" => (string) $kirby->user()->uuid()
|
||||||
"notifications" => Yaml::decode($kirby->user()->notifications()->value()),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($kirby->user()->role() == 'client' && $kirby->user()->client()->isNotEmpty()) {
|
if ($kirby->user()->client()->exists() && $kirby->user()->client()->isNotEmpty()) {
|
||||||
$userData['client'] = [
|
$userData['client'] = [
|
||||||
"name" => (string) $kirby->user()->client()->toPage()->title(),
|
"name" => (string) $kirby->user()->client()->toPage()->title(),
|
||||||
"uuid" => (string) $kirby->user()->client()->toPage()->uuid()
|
"uuid" => (string) $kirby->user()->client()->toPage()->uuid()
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ return [
|
||||||
try {
|
try {
|
||||||
$project->createNotification($commentData);
|
$project->createNotification($commentData);
|
||||||
} catch (\Throwable $th) {
|
} catch (\Throwable $th) {
|
||||||
throw new Exception($th->getMessage() . ". Line " . $th->getLine() . " in file " . $th->getFile(), 1);
|
throw new Exception($th->getMessage() . ". line " . $th->getLine() . " in file " . $th->getFile(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
exit;
|
exit;
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,18 @@ return [
|
||||||
'action' => function () {
|
'action' => function () {
|
||||||
$json = file_get_contents('php://input');
|
$json = file_get_contents('php://input');
|
||||||
$data = json_decode($json);
|
$data = json_decode($json);
|
||||||
|
|
||||||
$newNotifications = kirby()->user()->readNotification($data->notificationId);
|
try {
|
||||||
return $newNotifications;
|
$project = page($data->projectUuid);
|
||||||
|
$project->readNotification($data->notificationId);
|
||||||
|
return json_encode([
|
||||||
|
"status" => "success"
|
||||||
|
]);
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
return json_encode([
|
||||||
|
"status" => "error",
|
||||||
|
"message" => $th->getMessage() . ' line ' . $th->getLine() . " in file " . $th->getFile()
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
@ -12,7 +12,7 @@ class Notification
|
||||||
protected Author $author;
|
protected Author $author;
|
||||||
protected string $date;
|
protected string $date;
|
||||||
protected string $id;
|
protected string $id;
|
||||||
protected string $isread = "false";
|
protected array $readby = [];
|
||||||
|
|
||||||
protected ?Position $position = null;
|
protected ?Position $position = null;
|
||||||
|
|
||||||
|
|
@ -33,7 +33,7 @@ class Notification
|
||||||
"author" => $this->author->toArray(),
|
"author" => $this->author->toArray(),
|
||||||
"date" => $this->date,
|
"date" => $this->date,
|
||||||
"id" => $this->id,
|
"id" => $this->id,
|
||||||
"isread" => $this->isread,
|
"readby" => $this->readby,
|
||||||
];
|
];
|
||||||
|
|
||||||
return $array;
|
return $array;
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,36 @@ class NotificationsPage extends Page {
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->update([
|
$this->update([
|
||||||
'notifications' => Yaml::encode(array_values($notifications))
|
'notifications' => $notifications
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function readNotification($notificationId) {
|
||||||
|
$notifications = $this->notifications()->isNotEmpty()
|
||||||
|
? Yaml::decode($this->notifications()->value())
|
||||||
|
: [];
|
||||||
|
|
||||||
|
foreach ($notifications as $key => &$notification) {
|
||||||
|
if ($notification['id'] !== $notificationId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($notification["readby"])) {
|
||||||
|
$notification["readby"] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$userUuid = (string) kirby()->user()->uuid();
|
||||||
|
if (in_array($userUuid, $notification["readby"])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$notification["readby"][] = $userUuid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->update([
|
||||||
|
'notifications' => Yaml::encode($notifications)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -115,15 +115,15 @@ import { useProjectStore } from "../stores/project";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const isExpanded = ref(true);
|
const isExpanded = ref(true);
|
||||||
const { user } = storeToRefs(useUserStore());
|
const { user, notifications } = storeToRefs(useUserStore());
|
||||||
const { currentProjects, archivedProjects } = storeToRefs(useProjectsStore());
|
const { currentProjects, archivedProjects } = storeToRefs(useProjectsStore());
|
||||||
const { isEmptyBrief } = useProjectStore();
|
const { isEmptyBrief } = useProjectStore();
|
||||||
const { page } = storeToRefs(usePageStore());
|
const { page } = storeToRefs(usePageStore());
|
||||||
|
|
||||||
const unreadNotificationsCount = computed(() => {
|
const unreadNotificationsCount = computed(() => {
|
||||||
if (!user.value) return undefined;
|
if (!user.value) return undefined;
|
||||||
const count = user.value.notifications.filter(
|
const count = notifications.value.filter(
|
||||||
(notification) => notification.isread != "true"
|
(notification) => !notification.isRead
|
||||||
).length;
|
).length;
|
||||||
if (count === 0) return undefined;
|
if (count === 0) return undefined;
|
||||||
return count;
|
return count;
|
||||||
|
|
@ -168,7 +168,7 @@ function isCurrent(navItem) {
|
||||||
|
|
||||||
function hasUnreadNotification(project) {
|
function hasUnreadNotification(project) {
|
||||||
if (!user.value) return false;
|
if (!user.value) return false;
|
||||||
return user.value.notifications.some((notification) => {
|
return notifications.value.some((notification) => {
|
||||||
return (
|
return (
|
||||||
notification.isread != "true" &&
|
notification.isread != "true" &&
|
||||||
project.uri.includes(notification.location.project.uri)
|
project.uri.includes(notification.location.project.uri)
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ const getStatus = computed(() => {
|
||||||
const correspondingNotification = userStore.notifications.find(
|
const correspondingNotification = userStore.notifications.find(
|
||||||
(notification) => notification.id === comment.id
|
(notification) => notification.id === comment.id
|
||||||
);
|
);
|
||||||
if (correspondingNotification && correspondingNotification.isread != "true") {
|
if (correspondingNotification && !correspondingNotification.isRead) {
|
||||||
return "unread";
|
return "unread";
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
@ -143,7 +143,7 @@ function handleClick() {
|
||||||
async function read() {
|
async function read() {
|
||||||
if (getStatus.value !== "unread") return;
|
if (getStatus.value !== "unread") return;
|
||||||
try {
|
try {
|
||||||
const newNotification = await api.readNotification(comment.id);
|
const newNotification = await api.readNotification(comment);
|
||||||
console.log(newNotification);
|
console.log(newNotification);
|
||||||
userStore.readNotification(comment.id);
|
userStore.readNotification(comment.id);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<article
|
<article
|
||||||
class="notification | bg-white rounded-lg | p-16 | flow"
|
class="notification | bg-white rounded-lg | p-16 | flow"
|
||||||
:data-status="notification.isread == 'true' ? 'read' : 'unread'"
|
|
||||||
data-type="comment"
|
data-type="comment"
|
||||||
@click="router.push(notification.location.dialoguri + '&comments=true')"
|
@click="router.push(notification.location.dialoguri + '&comments=true')"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<article
|
<article
|
||||||
class="notification | bg-white rounded-lg | p-16 | flow"
|
class="notification | bg-white rounded-lg | p-16 | flow"
|
||||||
:data-status="notification.isread == 'true' ? 'read' : 'unread'"
|
|
||||||
data-type="content"
|
data-type="content"
|
||||||
@click="
|
@click="
|
||||||
read(notification);
|
read(notification);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<article
|
<article
|
||||||
class="notification | bg-white rounded-lg | p-16 | flow"
|
class="notification | bg-white rounded-lg | p-16 | flow"
|
||||||
:data-status="notification.isread == 'true' ? 'read' : 'unread'"
|
|
||||||
data-type="comment"
|
data-type="comment"
|
||||||
@click="router.push(notification.location.dialoguri + '&comments=true')"
|
@click="router.push(notification.location.dialoguri + '&comments=true')"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -2,35 +2,6 @@ import { defineStore } from "pinia";
|
||||||
import uniqid from "uniqid";
|
import uniqid from "uniqid";
|
||||||
|
|
||||||
export const useApiStore = defineStore("api", () => {
|
export const useApiStore = defineStore("api", () => {
|
||||||
/**
|
|
||||||
* Asynchronously fetches JSON data corresponding to a given path.
|
|
||||||
*
|
|
||||||
* @param {string} [path=window.location.pathname] - The path for which to fetch data.
|
|
||||||
* - If no path is provided, the function will use the current page's path.
|
|
||||||
* - If the path is "/", it is assumed to be the homepage, and "home.json" is fetched.
|
|
||||||
* - For other paths, the function will append ".json" to the path and fetch that URL.
|
|
||||||
*
|
|
||||||
* @returns {Promise<Object>} A promise that resolves to the JSON data if the fetch is successful.
|
|
||||||
*
|
|
||||||
* @throws {Error} Will throw an error if the HTTP request fails (e.g., non-200 status code).
|
|
||||||
* - The error will include the HTTP status code and a message indicating the fetch failed.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* // Fetch data for the current page
|
|
||||||
* fetchData().then(data => {
|
|
||||||
* console.log(data);
|
|
||||||
* }).catch(error => {
|
|
||||||
* console.error('Error fetching data:', error);
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* // Fetch data for a specific path
|
|
||||||
* fetchData('/about').then(data => {
|
|
||||||
* console.log(data);
|
|
||||||
* }).catch(error => {
|
|
||||||
* console.error('Error fetching data:', error);
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
async function fetchData(path = window.location.pathname) {
|
async function fetchData(path = window.location.pathname) {
|
||||||
const isHomePage = path === "/";
|
const isHomePage = path === "/";
|
||||||
path = path === "/" ? "/home" : path;
|
path = path === "/" ? "/home" : path;
|
||||||
|
|
@ -57,47 +28,6 @@ export const useApiStore = defineStore("api", () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchDataThroughKQL() {
|
|
||||||
const api = "/api/query";
|
|
||||||
|
|
||||||
const username = import.meta.env.VITE_USERNAME;
|
|
||||||
const password = import.meta.env.VITE_PASSWORD;
|
|
||||||
|
|
||||||
const token = btoa(`${username}:${password}`);
|
|
||||||
|
|
||||||
const headers = {
|
|
||||||
Authorization: `Basic ${token}`,
|
|
||||||
};
|
|
||||||
|
|
||||||
const request = {
|
|
||||||
method: "post",
|
|
||||||
body: JSON.stringify({
|
|
||||||
query: `page('home')`,
|
|
||||||
select: {
|
|
||||||
testImages: {
|
|
||||||
query: "page.testImages.toFiles",
|
|
||||||
select: {
|
|
||||||
url: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
blocks: {
|
|
||||||
query: "page.testBlocks.toBlocks",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
};
|
|
||||||
|
|
||||||
fetch(api, request)
|
|
||||||
.then((response) => response.json())
|
|
||||||
.then((response) => {
|
|
||||||
console.log(response);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchRoute(path, method, data) {
|
async function fetchRoute(path, method, data) {
|
||||||
const config = {
|
const config = {
|
||||||
method: method,
|
method: method,
|
||||||
|
|
@ -212,11 +142,12 @@ export const useApiStore = defineStore("api", () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function readNotification(notificationId) {
|
async function readNotification(comment) {
|
||||||
const headers = {
|
const headers = {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
notificationId,
|
projectUuid: comment.location.project.uuid,
|
||||||
|
notificationId: comment.id,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
|
|
@ -278,7 +209,6 @@ export const useApiStore = defineStore("api", () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fetchDataThroughKQL,
|
|
||||||
fetchData,
|
fetchData,
|
||||||
fetchRoute,
|
fetchRoute,
|
||||||
addComment,
|
addComment,
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,45 @@
|
||||||
import { defineStore } from "pinia";
|
import { defineStore, storeToRefs } from "pinia";
|
||||||
import { ref, computed } from "vue";
|
import { ref, computed } from "vue";
|
||||||
|
import { useProjectsStore } from "./projects";
|
||||||
|
|
||||||
export const useUserStore = defineStore("user", () => {
|
export const useUserStore = defineStore("user", () => {
|
||||||
const user = ref(null);
|
const user = ref(null);
|
||||||
|
|
||||||
|
const { projects } = storeToRefs(useProjectsStore());
|
||||||
|
|
||||||
const notifications = computed(() => {
|
const notifications = computed(() => {
|
||||||
return typeof user.value.notifications === "array"
|
return projects.value.reduce((acc, project) => {
|
||||||
? user.value.notifications
|
if (!project.notifications) return acc;
|
||||||
: Object.values(user.value.notifications);
|
|
||||||
|
const projectNotifications = project.notifications.map(
|
||||||
|
(notification) => ({
|
||||||
|
...notification,
|
||||||
|
project: {
|
||||||
|
id: project.id,
|
||||||
|
name: project.title,
|
||||||
|
},
|
||||||
|
isRead:
|
||||||
|
notification.author.uuid === user.value.uuid ||
|
||||||
|
notification.readby?.includes(user.value.uuid),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return [...acc, ...projectNotifications];
|
||||||
|
}, []);
|
||||||
});
|
});
|
||||||
|
|
||||||
function readNotification(notificationId) {
|
function readNotification(notificationId) {
|
||||||
user.value.notifications.forEach((notification) => {
|
notifications.value = notifications.value.map((notification) => {
|
||||||
if (notification.id === notificationId) {
|
if (notification.id === notificationId) {
|
||||||
notification.isread = "true";
|
notification.isRead = true;
|
||||||
}
|
}
|
||||||
|
return notification;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function readAllNotifications(notificationId) {
|
function readAllNotifications(notificationId) {
|
||||||
user.value.notifications.forEach((notification) => {
|
user.value.notifications.forEach((notification) => {
|
||||||
notification.isread = true;
|
notification.isRead = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@
|
||||||
<component
|
<component
|
||||||
:is="notificationComponents[notification.type]"
|
:is="notificationComponents[notification.type]"
|
||||||
:notification="notification"
|
:notification="notification"
|
||||||
|
:data-status="notification.isRead ? 'read' : 'unread'"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue