Adds Messaging streaming
This commit is contained in:
64
src/internal_time_ago.js
Normal file
64
src/internal_time_ago.js
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
export function time_ago(time) {
|
||||||
|
const time_date = new Date(time)
|
||||||
|
const now_date = new Date(Date.now())
|
||||||
|
const ago = now_date - time_date
|
||||||
|
return internal_time_ago(ago)
|
||||||
|
}
|
||||||
|
|
||||||
|
function internal_time_ago(time) {
|
||||||
|
|
||||||
|
switch (typeof time) {
|
||||||
|
case 'number':
|
||||||
|
break;
|
||||||
|
case 'string':
|
||||||
|
time = +new Date(time);
|
||||||
|
break;
|
||||||
|
case 'object':
|
||||||
|
if (time.constructor === Date) time = time.getTime();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
time = +new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
const time_formats = [
|
||||||
|
[60, 'seconds', 1], // 60
|
||||||
|
[120, '1 minute ago', '1 minute from now'], // 60*2
|
||||||
|
[3600, 'minutes', 60], // 60*60, 60
|
||||||
|
[7200, '1 hour ago', '1 hour from now'], // 60*60*2
|
||||||
|
[86400, 'hours', 3600], // 60*60*24, 60*60
|
||||||
|
[172800, 'Yesterday', 'Tomorrow'], // 60*60*24*2
|
||||||
|
[604800, 'days', 86400], // 60*60*24*7, 60*60*24
|
||||||
|
[1209600, 'Last week', 'Next week'], // 60*60*24*7*4*2
|
||||||
|
[2419200, 'weeks', 604800], // 60*60*24*7*4, 60*60*24*7
|
||||||
|
[4838400, 'Last month', 'Next month'], // 60*60*24*7*4*2
|
||||||
|
[29030400, 'months', 2419200], // 60*60*24*7*4*12, 60*60*24*7*4
|
||||||
|
[58060800, 'Last year', 'Next year'], // 60*60*24*7*4*12*2
|
||||||
|
[2903040000, 'years', 29030400], // 60*60*24*7*4*12*100, 60*60*24*7*4*12
|
||||||
|
[5806080000, 'Last century', 'Next century'], // 60*60*24*7*4*12*100*2
|
||||||
|
[58060800000, 'centuries', 2903040000] // 60*60*24*7*4*12*100*20, 60*60*24*7*4*12*100
|
||||||
|
];
|
||||||
|
|
||||||
|
let seconds = time / 1000
|
||||||
|
|
||||||
|
let token = 'ago'
|
||||||
|
let list_choice = 1
|
||||||
|
|
||||||
|
if (seconds === 0) {
|
||||||
|
return 'Just now'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seconds < 0) {
|
||||||
|
seconds = Math.abs(seconds);
|
||||||
|
token = 'from now';
|
||||||
|
list_choice = 2;
|
||||||
|
}
|
||||||
|
let i = 0, format;
|
||||||
|
while (format = time_formats[i++])
|
||||||
|
if (seconds < format[0]) {
|
||||||
|
if (typeof format[2] == 'string')
|
||||||
|
return format[list_choice];
|
||||||
|
else
|
||||||
|
return Math.floor(seconds / format[2]) + ' ' + format[1] + ' ' + token;
|
||||||
|
}
|
||||||
|
return time;
|
||||||
|
}
|
||||||
@@ -2,7 +2,12 @@
|
|||||||
|
|
||||||
<div class="shadow-lg rounded-lg">
|
<div class="shadow-lg rounded-lg">
|
||||||
|
|
||||||
<div class="text-lg font-bold">{{ props.content.title }}</div>
|
<div class="text-lg font-bold">
|
||||||
|
{{ props.content.title }}
|
||||||
|
<span class="text-md-caption">
|
||||||
|
{{ time_ago(props.content.createdAt) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="h-48 object-cover bg-purple rounded-md">
|
<div class="h-48 object-cover bg-purple rounded-md">
|
||||||
|
|
||||||
@@ -39,11 +44,11 @@
|
|||||||
|
|
||||||
<div class="border-b p-6">
|
<div class="border-b p-6">
|
||||||
<h2 class="font-sans font-semibold">Commentaires</h2>
|
<h2 class="font-sans font-semibold">Commentaires</h2>
|
||||||
<MessageList :content-id="props.content.id">
|
<MessageList :subject-id="props.content.id">
|
||||||
</MessageList>
|
</MessageList>
|
||||||
</div>
|
</div>
|
||||||
<div class="border-b-2 p-6">
|
<div class="border-b-2 p-6">
|
||||||
<PostMessage :content-id="props.content.id">
|
<PostMessage :subject-id="props.content.id">
|
||||||
</PostMessage>
|
</PostMessage>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -57,6 +62,7 @@
|
|||||||
import {defineProps, computed} from 'vue';
|
import {defineProps, computed} from 'vue';
|
||||||
import MessageList from "@/views/messages/MessageList.vue";
|
import MessageList from "@/views/messages/MessageList.vue";
|
||||||
import PostMessage from "@/views/messages/PostMessage.vue";
|
import PostMessage from "@/views/messages/PostMessage.vue";
|
||||||
|
import {time_ago} from "@/internal_time_ago.js";
|
||||||
|
|
||||||
const isHttpUrl = computed(() => props.content?.uri?.startsWith('http'))
|
const isHttpUrl = computed(() => props.content?.uri?.startsWith('http'))
|
||||||
|
|
||||||
|
|||||||
@@ -37,13 +37,13 @@ const props = defineProps({
|
|||||||
|
|
||||||
const client = useClient()
|
const client = useClient()
|
||||||
const contents = ref([])
|
const contents = ref([])
|
||||||
const max_items = 10
|
const page_size = 10
|
||||||
const errorMessage = ref()
|
const errorMessage = ref()
|
||||||
let last_id = null
|
let last_id = null
|
||||||
|
|
||||||
async function load({done}) {
|
async function load({done}) {
|
||||||
try {
|
try {
|
||||||
let uri = `/api/contents/user/${props.creatorId}?max_items=${max_items}`
|
let uri = `/api/contents/user/${props.creatorId}?page_size=${page_size}`
|
||||||
if (last_id !== null) uri = uri + `&last_id=${last_id}`
|
if (last_id !== null) uri = uri + `&last_id=${last_id}`
|
||||||
|
|
||||||
console.log(`Fetching content at: ${uri}`)
|
console.log(`Fetching content at: ${uri}`)
|
||||||
@@ -59,7 +59,7 @@ async function load({done}) {
|
|||||||
last_id = last_content.id
|
last_id = last_content.id
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contentCount < max_items)
|
if (contentCount < page_size)
|
||||||
done('empty')
|
done('empty')
|
||||||
else
|
else
|
||||||
done('ok')
|
done('ok')
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<seize-indicator></seize-indicator>
|
<size-indicator></size-indicator>
|
||||||
|
|
||||||
<!-- Bannière-->
|
<!-- Bannière-->
|
||||||
<div class="relative bottom-4 z-20 m">
|
<div class="relative bottom-4 z-20 m">
|
||||||
@@ -82,8 +82,8 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import CreatePostButton from "@/views/contents/CreatePostButton.vue";
|
import CreatePostButton from "@/views/contents/CreatePostButton.vue";
|
||||||
import {defineProps, ref} from "vue";
|
import {defineProps} from "vue";
|
||||||
import SeizeIndicator from "@/views/tools/SeizeIndicator.vue";
|
import SizeIndicator from "@/views/tools/SizeIndicator.vue";
|
||||||
import AboutYou from "@/views/creators/AboutYou.vue";
|
import AboutYou from "@/views/creators/AboutYou.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<div>
|
<div>
|
||||||
<span class="font-semibold font-sans mr-2">{{ message.createdBy }}</span>
|
<span class="font-semibold font-sans mr-2">{{ message.createdBy }}</span>
|
||||||
<span class="text-sm font-sans text-gray-700">il y a 3 heures</span>
|
<span class="text-sm font-sans text-gray-700">{{ time_ago(message.createdAt) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<v-menu>
|
<v-menu>
|
||||||
<template v-slot:activator="{ props }">
|
<template v-slot:activator="{ props }">
|
||||||
@@ -43,28 +43,32 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
export default {
|
|
||||||
props: {
|
import {defineProps} from "vue"
|
||||||
message: {
|
import {time_ago} from "@/internal_time_ago.js";
|
||||||
type: Object,
|
|
||||||
required: true
|
const props = defineProps({
|
||||||
}
|
message: {
|
||||||
},
|
type: Object,
|
||||||
methods: {
|
required: true
|
||||||
editMessage(message) {
|
|
||||||
// Logic for editing the message
|
|
||||||
console.log('Edit message', message);
|
|
||||||
},
|
|
||||||
deleteMessage(message) {
|
|
||||||
// Logic for deleting the message
|
|
||||||
console.log('Delete message', message);
|
|
||||||
},
|
|
||||||
reportMessage(message) {
|
|
||||||
// Logic for reporting the message
|
|
||||||
console.log('Report message', message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function editMessage(message) {
|
||||||
|
// Logic for editing the message
|
||||||
|
console.log('Edit message', message);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteMessage(message) {
|
||||||
|
// Logic for deleting the message
|
||||||
|
console.log('Delete message', message);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reportMessage(message) {
|
||||||
|
// Logic for reporting the message
|
||||||
|
console.log('Report message', message);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,40 +1,99 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div v-for="(message, index) in messages" :key="index">
|
<v-infinite-scroll :items="messages"
|
||||||
<Message :message="message"></Message>
|
:onLoad="load"
|
||||||
</div>
|
mode="manual"
|
||||||
|
class="bg-teal justify-items-center">
|
||||||
|
|
||||||
|
<template v-for="(message, index) in messages" :key="index">
|
||||||
|
<Message
|
||||||
|
:message="message"
|
||||||
|
class="my-2 p-4 bg-amber-200 w-full"
|
||||||
|
>
|
||||||
|
</Message>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:load-more="{ props }">
|
||||||
|
<v-btn
|
||||||
|
size="small"
|
||||||
|
variant="flat"
|
||||||
|
v-bind="props"
|
||||||
|
>Voir plus de commentaires
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:empty>
|
||||||
|
Il n'y a pas plus de commentaires
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:error>
|
||||||
|
<v-alert type="error">{{ errorMessage }}</v-alert>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</v-infinite-scroll>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|
||||||
import Message from "@/views/messages/Message.vue";
|
import Message from "@/views/messages/Message.vue";
|
||||||
// import posts from "@/views/posts/posts.json";
|
|
||||||
|
|
||||||
import {useClient} from '@/plugins/api.js';
|
import {useClient} from '@/plugins/api.js';
|
||||||
import {defineProps, onBeforeMount, ref} from 'vue';
|
import {defineProps, onBeforeMount, ref} from 'vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
contentId: {
|
subjectId: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const errorMessage = ref()
|
||||||
|
let last_id = null
|
||||||
const client = useClient();
|
const client = useClient();
|
||||||
const messages = ref();
|
const messages = ref([]);
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(async () => {
|
||||||
if (props.contentId == null) return
|
if (props.subjectId == null) return
|
||||||
|
await load({
|
||||||
try {
|
page_size: 2,
|
||||||
const response = await client.get(`/api/messages/${props.contentId}`)
|
done: function (status) {
|
||||||
if (response.status >= 200 && response.status < 300) {
|
console.log(`Loading status: ${status}`)
|
||||||
messages.value = response.data
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
})
|
||||||
console.error("Failed to fetch messages", error);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
async function load({done, page_size}) {
|
||||||
|
if (props.subjectId == null) return
|
||||||
|
if (page_size === undefined) page_size = 10
|
||||||
|
|
||||||
|
try {
|
||||||
|
let uri = `/api/messages/${props.subjectId}?page_size=${page_size}`
|
||||||
|
if (last_id !== null) uri = uri + `&last_id=${last_id}`
|
||||||
|
|
||||||
|
console.log(`Fetching messages at: ${uri}`)
|
||||||
|
const response = await client.get(uri)
|
||||||
|
|
||||||
|
if (response.status >= 200 && response.status < 300) {
|
||||||
|
|
||||||
|
const messageCount = response.data.length
|
||||||
|
|
||||||
|
if (messageCount > 0) {
|
||||||
|
messages.value.push(...response.data)
|
||||||
|
const [last_content] = response.data.slice(-1)
|
||||||
|
last_id = last_content.id
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messageCount < page_size)
|
||||||
|
done('empty')
|
||||||
|
else
|
||||||
|
done('ok')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to fetch posts", error);
|
||||||
|
errorMessage.value = error
|
||||||
|
done('error')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -39,7 +39,7 @@ import {useClient} from '@/plugins/api.js';
|
|||||||
import {defineProps, ref} from 'vue';
|
import {defineProps, ref} from 'vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
contentId: {
|
subjectId: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ const publish = async () => {
|
|||||||
await client.post(
|
await client.post(
|
||||||
`/api/messages/`,
|
`/api/messages/`,
|
||||||
{
|
{
|
||||||
"subjectId": props.contentId,
|
"subjectId": props.subjectId,
|
||||||
"message": message.value
|
"message": message.value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user