more stores
This commit is contained in:
@@ -1,76 +1,41 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import Markdown from "@/components/quick/Markdown.vue";
|
import Markdown from "@/components/quick/Markdown.vue";
|
||||||
|
|
||||||
import { ref, onMounted } from "vue";
|
import { ref, computed, onMounted } from "vue";
|
||||||
import axios from "axios";
|
|
||||||
import { useAuthStore } from "@/stores/auth";
|
import { useAuthStore } from "@/stores/auth";
|
||||||
|
import { usePostsStore } from "@/stores/posts";
|
||||||
|
|
||||||
const auth = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const userOwnsPost = ref(false);
|
const postsStore = usePostsStore();
|
||||||
|
|
||||||
const post = ref({
|
const idx = ref(0);
|
||||||
title: "Can't fetch from the db yo",
|
|
||||||
content:
|
|
||||||
"This is meant to be pulling from a database, but for some reason that isn't working and this is filler text that should hopefully never see the light of day. If you are reading this, something has gone horribly, horribly wrong. Please start crying and prepare for the incoming wrath of hell. Furthermore, this is very, very long because I am trying to test the scroll feature so thank you ^_^.",
|
|
||||||
author: {
|
|
||||||
username: "stp",
|
|
||||||
},
|
|
||||||
createdAt: Date.now(),
|
|
||||||
});
|
|
||||||
const leftCap = ref(false);
|
|
||||||
const rightCap = ref(false);
|
|
||||||
let posts = [];
|
|
||||||
let idx = 0;
|
|
||||||
let len = 0;
|
|
||||||
|
|
||||||
async function fetchPosts() {
|
const leftCap = computed(() => idx.value === 0);
|
||||||
try {
|
const rightCap = computed(() => idx.value === postsStore.postsCount - 1);
|
||||||
const res = await axios.get("/api/posts");
|
|
||||||
if (!Array.isArray(res.data)) {
|
const post = computed(() => postsStore.posts[idx.value]);
|
||||||
throw new Error("Invalid response from posts API");
|
const userOwnsPost = computed(
|
||||||
}
|
() => post.value.author.username == authStore.user.username,
|
||||||
posts = res.data;
|
);
|
||||||
len = posts.length;
|
|
||||||
post.value = posts[0];
|
|
||||||
userOwnsPost.value = post.value.author.username == auth.user.username;
|
|
||||||
leftCap.value = true;
|
|
||||||
} catch (err) {
|
|
||||||
console.log("Cannot connect to API");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function nextPost() {
|
function nextPost() {
|
||||||
if (idx < len - 1) {
|
if (idx.value < postsStore.postsCount - 1) {
|
||||||
idx++;
|
idx.value++;
|
||||||
rightCap.value = idx === len - 1;
|
|
||||||
leftCap.value = idx === 0;
|
|
||||||
post.value = posts[idx];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function prevPost() {
|
function prevPost() {
|
||||||
if (idx > 0) {
|
if (idx.value > 0) {
|
||||||
idx--;
|
idx.value--;
|
||||||
rightCap.value = idx === len - 1;
|
|
||||||
leftCap.value = idx === 0;
|
|
||||||
post.value = posts[idx];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deletePost() {
|
function deletePost() {
|
||||||
try {
|
postsStore.deletePost(post.value);
|
||||||
const res = await axios.delete(
|
|
||||||
`/api/posts/${encodeURIComponent(post.value.id)}`,
|
|
||||||
);
|
|
||||||
console.log("Deleted:", res.data);
|
|
||||||
fetchPosts();
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Delete failed:", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchPosts();
|
postsStore.fetchPosts();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,55 +1,28 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted, onUnmounted } from "vue";
|
import { ref, computed, onMounted, onUnmounted } from "vue";
|
||||||
import axios from "axios";
|
import { useSongsStore } from "@/stores/songs";
|
||||||
|
|
||||||
|
const songsStore = useSongsStore();
|
||||||
|
const idx = ref(0);
|
||||||
|
const song = computed(() => songsStore.songs[idx.value]);
|
||||||
|
|
||||||
let nextId = null;
|
let nextId = null;
|
||||||
let refreshId = null;
|
let refreshId = null;
|
||||||
|
|
||||||
const song = computed(() => songs.value[idx.value]);
|
|
||||||
const songs = ref([
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
track: {
|
|
||||||
id: 1,
|
|
||||||
name: "^_^",
|
|
||||||
album: { images: [{ url: "/img/Untitled.png" }] },
|
|
||||||
artists: [{ name: ">_<" }],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
const idx = ref(0);
|
|
||||||
|
|
||||||
async function fetchRecent() {
|
|
||||||
try {
|
|
||||||
const res = await axios.get("/api/spotify/recent");
|
|
||||||
if (!Array.isArray(res.data)) {
|
|
||||||
throw new Error("Invalid response from Spotify API");
|
|
||||||
}
|
|
||||||
|
|
||||||
songs.value = res.data;
|
|
||||||
idx.value = 0;
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Cannot connect to Spotify API", err);
|
|
||||||
}
|
|
||||||
refreshId = setTimeout(fetchRecent, 120000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function nextSong() {
|
function nextSong() {
|
||||||
clearTimeout(nextId);
|
clearTimeout(nextId);
|
||||||
if (!songs.value.length) return;
|
|
||||||
idx.value = (idx.value + 1) % songs.value.length;
|
|
||||||
nextId = setTimeout(nextSong, 5000);
|
nextId = setTimeout(nextSong, 5000);
|
||||||
|
idx.value = (idx.value + 1) % songsStore.songsCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(() => {
|
||||||
await fetchRecent();
|
|
||||||
nextId = setTimeout(nextSong, 5000);
|
nextId = setTimeout(nextSong, 5000);
|
||||||
refreshId = setTimeout(fetchRecent, 120000);
|
refreshId = setInterval(songsStore.fetchSongs, 120000);
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
clearTimeout(nextId);
|
clearTimeout(nextId);
|
||||||
clearTimeout(refreshId);
|
clearInterval(refreshId);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +1,14 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, onUnmounted, ref } from "vue";
|
import { useMessagesStore } from "@/stores/messages";
|
||||||
// Connect to websocket
|
|
||||||
const url = "/api/ws";
|
|
||||||
|
|
||||||
const socket = ref(null);
|
const messagesStore = useMessagesStore();
|
||||||
const messages = ref([]);
|
const messages = computed(() => messagesStore.messages);
|
||||||
const messageInput = ref(
|
|
||||||
"This will work soon but for now is bait, please don't worry... it will all come together soon :)",
|
|
||||||
);
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
socket.value = new WebSocket(url);
|
messagesStore.connect();
|
||||||
|
|
||||||
socket.value.addEventListener("message", (event) => {
|
|
||||||
const message = JSON.parse(event.data);
|
|
||||||
messages.value.push(message);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function sendMessage() {
|
|
||||||
socket.value.send(JSON.stringify({ content: messageInput.value }));
|
|
||||||
messageInput.value = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
socket.value?.close();
|
messagesStore.disconnect();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import axios from "axios";
|
|||||||
|
|
||||||
export const useAuthStore = defineStore("auth", () => {
|
export const useAuthStore = defineStore("auth", () => {
|
||||||
const user = ref({});
|
const user = ref({});
|
||||||
checkToken();
|
|
||||||
|
|
||||||
const loggedIn = computed(() => !!user.value.username);
|
const loggedIn = computed(() => !!user.value.username);
|
||||||
|
|
||||||
|
checkToken();
|
||||||
|
|
||||||
async function logOut() {
|
async function logOut() {
|
||||||
try {
|
try {
|
||||||
const res = await axios.post("/api/auth/logout");
|
const res = await axios.post("/api/auth/logout");
|
||||||
@@ -61,11 +61,13 @@ export const useAuthStore = defineStore("auth", () => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
user,
|
user,
|
||||||
checkToken,
|
|
||||||
|
loggedIn,
|
||||||
|
|
||||||
logIn,
|
logIn,
|
||||||
|
checkToken,
|
||||||
refreshToken,
|
refreshToken,
|
||||||
logOut,
|
logOut,
|
||||||
createUser,
|
createUser,
|
||||||
loggedIn,
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
77
nginx/vue/src/stores/messages.js
Normal file
77
nginx/vue/src/stores/messages.js
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import { defineStore } from "pinia";
|
||||||
|
import { ref, computed } from "vue";
|
||||||
|
|
||||||
|
const URL = "/api/ws";
|
||||||
|
|
||||||
|
const message_template = {
|
||||||
|
id: 0,
|
||||||
|
content: "Yo",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMessagesStore = defineStore("messages", () => {
|
||||||
|
const socket = ref(null);
|
||||||
|
const messages = ref([message_template]);
|
||||||
|
const isConnected = ref(false);
|
||||||
|
const lastError = ref(null);
|
||||||
|
|
||||||
|
const messagesCount = computed(() => messages.value.length);
|
||||||
|
|
||||||
|
function connect() {
|
||||||
|
if (socket.value && isConnected.value) return;
|
||||||
|
|
||||||
|
socket.value = new WebSocket(URL);
|
||||||
|
|
||||||
|
socket.value.onopen = () => {
|
||||||
|
isConnected.value = true;
|
||||||
|
lastError.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.value.onmessage = (event) => {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
messages.value.push(data);
|
||||||
|
} catch {
|
||||||
|
// fallback if server sends plain text
|
||||||
|
messages.value.push(event.data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.value.onerror = (error) => {
|
||||||
|
lastError.value = error;
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.value.onclose = () => {
|
||||||
|
isConnected.value = false;
|
||||||
|
socket.value = null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function disconnect() {
|
||||||
|
if (!socket.value) return;
|
||||||
|
socket.value.close();
|
||||||
|
socket.value = null;
|
||||||
|
isConnected.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendMessage(payload) {
|
||||||
|
if (!socket.value || !isConnected.value) return;
|
||||||
|
socket.value.send(JSON.stringify(payload));
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearMessages() {
|
||||||
|
messages.value = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
messages,
|
||||||
|
isConnected,
|
||||||
|
lastError,
|
||||||
|
|
||||||
|
messagesCount,
|
||||||
|
|
||||||
|
connect,
|
||||||
|
disconnect,
|
||||||
|
sendMessage,
|
||||||
|
clearMessages,
|
||||||
|
};
|
||||||
|
});
|
||||||
48
nginx/vue/src/stores/models.js
Normal file
48
nginx/vue/src/stores/models.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
export class User {
|
||||||
|
constructor({ id, createdAt, updatedAt, deletedAt, username, admin }) {
|
||||||
|
this.id = id;
|
||||||
|
this.createdAt = new Date(createdAt);
|
||||||
|
this.updatedAt = new Date(updatedAt);
|
||||||
|
this.deletedAt = deletedAt ? new Date(deletedAt) : null;
|
||||||
|
this.username = username;
|
||||||
|
this.admin = admin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Message {
|
||||||
|
constructor({ id, text, author, createdAt, deletedAt }) {
|
||||||
|
this.id = id;
|
||||||
|
this.content = text;
|
||||||
|
this.author = author ? new User(author) : null;
|
||||||
|
this.createdAt = new Date(createdAt);
|
||||||
|
this.deletedAt = deletedAt ? new Date(deletedAt) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Post {
|
||||||
|
constructor({
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
author,
|
||||||
|
authorID,
|
||||||
|
content,
|
||||||
|
createdAt,
|
||||||
|
updatedAt,
|
||||||
|
deletedAt,
|
||||||
|
}) {
|
||||||
|
this.id = id;
|
||||||
|
this.title = title;
|
||||||
|
this.authorID = authorID;
|
||||||
|
this.author = author ? new User(author) : null;
|
||||||
|
this.content = content;
|
||||||
|
this.createdAt = new Date(createdAt);
|
||||||
|
this.updatedAt = new Date(updatedAt);
|
||||||
|
this.deletedAt = deletedAt ? new Date(deletedAt) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility function to parse posts from API
|
||||||
|
export function parsePosts(postsArray) {
|
||||||
|
if (!Array.isArray(postsArray)) return [];
|
||||||
|
return postsArray.map((post) => new Post(post));
|
||||||
|
}
|
||||||
51
nginx/vue/src/stores/posts.js
Normal file
51
nginx/vue/src/stores/posts.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import { defineStore } from "pinia";
|
||||||
|
import { computed, ref } from "vue";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
const post_template = {
|
||||||
|
title: "Can't fetch from the db yo",
|
||||||
|
content:
|
||||||
|
"This is meant to be pulling from a database, but for some reason that isn't working and this is filler text that should hopefully never see the light of day. If you are reading this, something has gone horribly, horribly wrong. Please start crying and prepare for the incoming wrath of hell. Furthermore, this is very, very long because I am trying to test the scroll feature so thank you ^_^.",
|
||||||
|
author: {
|
||||||
|
username: "stp",
|
||||||
|
},
|
||||||
|
createdAt: Date.now(),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePostsStore = defineStore("posts", () => {
|
||||||
|
const posts = ref([post_template]);
|
||||||
|
|
||||||
|
const postsCount = computed(() => posts.value.length);
|
||||||
|
|
||||||
|
async function fetchPosts() {
|
||||||
|
try {
|
||||||
|
const res = await axios.get("/api/posts");
|
||||||
|
if (!Array.isArray(res.data)) {
|
||||||
|
throw new Error("Invalid response from posts API");
|
||||||
|
}
|
||||||
|
posts.value = res.data;
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Cannot connect to Post API", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deletePost(post) {
|
||||||
|
try {
|
||||||
|
const res = await axios.delete(
|
||||||
|
`/api/posts/${encodeURIComponent(post.id)}`,
|
||||||
|
);
|
||||||
|
console.log("Deleted:", res.data);
|
||||||
|
fetchPosts();
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Delete failed:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
posts,
|
||||||
|
|
||||||
|
postsCount,
|
||||||
|
|
||||||
|
fetchPosts,
|
||||||
|
deletePost,
|
||||||
|
};
|
||||||
|
});
|
||||||
46
nginx/vue/src/stores/songs.js
Normal file
46
nginx/vue/src/stores/songs.js
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { defineStore } from "pinia";
|
||||||
|
import { ref, computed } from "vue";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
const song_template = {
|
||||||
|
id: 1,
|
||||||
|
track: {
|
||||||
|
id: 1,
|
||||||
|
name: "^_^",
|
||||||
|
album: { images: [{ url: "/img/Untitled.png" }] },
|
||||||
|
artists: [{ name: ">_<" }],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useSongsStore = defineStore("songs", () => {
|
||||||
|
const songs = ref([song_template]);
|
||||||
|
|
||||||
|
const songsCount = computed(() => songs.value.length);
|
||||||
|
|
||||||
|
fetchSongs();
|
||||||
|
|
||||||
|
let refreshId = null;
|
||||||
|
refreshId = setTimeout(fetchSongs, 120000);
|
||||||
|
|
||||||
|
async function fetchSongs() {
|
||||||
|
try {
|
||||||
|
const res = await axios.get("/api/spotify/recent");
|
||||||
|
if (!Array.isArray(res.data)) {
|
||||||
|
throw new Error("Invalid response from Spotify API");
|
||||||
|
}
|
||||||
|
songs.value = res.data;
|
||||||
|
refreshId = setTimeout(fetchSongs, 120000);
|
||||||
|
console.log("lol");
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Cannot connect to Spotify API", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
songs,
|
||||||
|
|
||||||
|
songsCount,
|
||||||
|
|
||||||
|
fetchSongs,
|
||||||
|
};
|
||||||
|
});
|
||||||
0
nginx/vue/src/stores/users.js
Normal file
0
nginx/vue/src/stores/users.js
Normal file
@@ -20,7 +20,7 @@ import Watching from "@/components/home/Watching.vue";
|
|||||||
<div class="flex-col tr">
|
<div class="flex-col tr">
|
||||||
<Time class="bdr-2 bg-primary" />
|
<Time class="bdr-2 bg-primary" />
|
||||||
<Timer class="bdr-2 bg-primary" />
|
<Timer class="bdr-2 bg-primary" />
|
||||||
<Chat class="bdr-2 bg-primary" />
|
<!-- <Chat class="bdr-2 bg-primary" /> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="background halftone" />
|
<div class="background halftone" />
|
||||||
|
|||||||
Reference in New Issue
Block a user