diff --git a/components/Message.vue b/components/Message.vue index a6d95ac..592a995 100644 --- a/components/Message.vue +++ b/components/Message.vue @@ -55,10 +55,6 @@ const dateHidden = ref(true); const date = new Date(props.timestamp); -console.log("Message.vue: message:", props.text); -console.log("Message.vue: message type:", props.type); -console.log("Message.vue: is last?", props.last); - let dateHour = date.getHours(); let dateMinute = date.getMinutes(); if (props.format == "12") { @@ -75,7 +71,12 @@ if (props.format == "12") { messageDate.value = `${dateHour}:${dateMinute < 10 ? "0" + dateMinute : dateMinute}` } -onMounted(() => { +console.log("message:", props.text); +console.log("author:", props.username); + +onMounted(async () => { + console.log("adding listeners") + await nextTick(); messageElement.value?.addEventListener("mouseenter", (e: Event) => { dateHidden.value = false; }); @@ -83,6 +84,7 @@ onMounted(() => { messageElement.value?.addEventListener("mouseleave", (e: Event) => { dateHidden.value = true; }); + console.log("added listeners"); }); //function toggleTooltip(e: Event) { diff --git a/components/MessageArea.vue b/components/MessageArea.vue index ff523cf..5ad027c 100644 --- a/components/MessageArea.vue +++ b/components/MessageArea.vue @@ -4,7 +4,7 @@
@@ -34,50 +34,65 @@ const messagesRes: MessageResponse[] | undefined = await fetchWithApi( { query: { "amount": props.amount ?? 100, "offset": props.offset ?? 0 } } ); -function groupMessage(message: MessageResponse) { - messageTimestamps.value[message.uuid] = uuidToTimestamp(message.uuid); +const firstMessageByUsers = ref>({}); +const previousMessage = ref(); - console.log("message:", message.message); - const firstByUser = firstMessageByUsers.value[message.user.uuid]; - if (firstByUser) { - console.log("first by user exists"); - if (message.user.uuid != firstByUser.user.uuid) { - console.log("message is by new user, setting their first message") - firstMessageByUsers.value[message.user.uuid] = message; - console.log("RETURNING FALSE"); - messagesType.value[message.uuid] = "normal"; - return; - } - } else { - console.log("first by user doesn't exist"); - console.log(`setting first post by user ${message.user.username} to "${message.message}" with timestamp ${messageTimestamps.value[message.uuid]}`); +function groupMessage(message: MessageResponse, options?: { prevMessage?: MessageResponse, reverse?: boolean }) { + messageTimestamps.value[message.uuid] = uuidToTimestamp(message.uuid); + console.log("message:", message.message); + console.log("author:", message.user.username, `(${message.user.uuid})`); + + if (!previousMessage.value || previousMessage.value && message.user.uuid != previousMessage.value.user.uuid) { + console.log("no previous message or author is different than last messsage's"); + messagesType.value[message.uuid] = "normal"; + previousMessage.value = message; + console.log("set previous message to:", previousMessage.value.message); + console.log(`setting first post by user ${message.user.username} to "${message.message}" with timestamp ${messageTimestamps.value[message.uuid]}`); + firstMessageByUsers.value[message.user.uuid] = message; + return; + } + + + const firstByUser = firstMessageByUsers.value[message.user.uuid]; + if (firstByUser) { + console.log("first by user exists:", firstByUser); + if (message.user.uuid != firstByUser.user.uuid) { + console.log("message is by new user, setting their first message") firstMessageByUsers.value[message.user.uuid] = message; console.log("RETURNING FALSE"); messagesType.value[message.uuid] = "normal"; return; } - - const prevTimestamp = messageTimestamps.value[firstByUser.uuid]; - const timestamp = messageTimestamps.value[message.uuid]; - console.log("first message timestamp:", prevTimestamp); - console.log("timestamp:", timestamp); - const diff = (timestamp - prevTimestamp); - console.log("min diff:", messageGroupingMaxDifference); - console.log("diff:", diff); - const lessThanMax = diff <= messageGroupingMaxDifference; - console.log("group?", lessThanMax); - if (!lessThanMax) { - console.log("diff exceeds max"); - console.log(`setting first post by user ${message.user.username} to "${message.message}" with timestamp ${messageTimestamps.value[message.uuid]}`) - firstMessageByUsers.value[message.user.uuid] = message; - messagesType.value[message.uuid] = "normal"; - return; - } - console.log("RETURNING " + lessThanMax.toString().toUpperCase()); - messagesType.value[message.uuid] = "grouped"; + } else { + console.log("first by user doesn't exist"); + console.log(`setting first post by user ${message.user.username} to "${message.message}" with timestamp ${messageTimestamps.value[message.uuid]}`); + firstMessageByUsers.value[message.user.uuid] = message; + console.log("RETURNING FALSE"); + messagesType.value[message.uuid] = "normal"; + return; + } + + const prevTimestamp = messageTimestamps.value[firstByUser.uuid]; + const timestamp = messageTimestamps.value[message.uuid]; + + console.log("first message timestamp:", prevTimestamp); + console.log("timestamp:", timestamp); + const diff = Math.abs(timestamp - prevTimestamp); + console.log("min diff:", messageGroupingMaxDifference); + console.log("diff:", diff); + const lessThanMax = diff <= messageGroupingMaxDifference; + console.log("group?", lessThanMax); + if (!lessThanMax) { + console.log("diff exceeds max"); + console.log(`setting first post by user ${message.user.username} to "${message.message}" with timestamp ${messageTimestamps.value[message.uuid]}`) + firstMessageByUsers.value[message.user.uuid] = message; + messagesType.value[message.uuid] = "normal"; + return; + } + console.log("RETURNING " + lessThanMax.toString().toUpperCase()); + messagesType.value[message.uuid] = "grouped"; } -const firstMessageByUsers = ref>({}); if (messagesRes) { messagesRes.reverse(); console.log("messages res:", messagesRes.map(msg => msg.message)); @@ -97,6 +112,7 @@ if (messagesRes) messages.value = messagesRes; const accessToken = useCookie("access_token").value; const apiBase = useCookie("api_base").value; const { refresh } = useAuth(); +const { fetchMessages } = useApi(); let ws: WebSocket; @@ -147,9 +163,42 @@ function sendMessage(e: Event) { } } +const route = useRoute(); + onMounted(async () => { + if (import.meta.server) return; if (messagesElement.value) { scrollToBottom(messagesElement); + let fetched = false; + const amount = messages.value.length; + let offset = messages.value.length; + messagesElement.value.addEventListener("scroll", async (e) => { + if (e.target) { + const target = e.target as HTMLDivElement; + if (target.scrollTop <= target.scrollHeight * 0.1) { + if (fetched) return; + fetched = true; + console.log("scroll height is at 10% or less"); + //console.log("current oldest:", currentOldestMessage); + const olderMessages = await fetchMessages(route.params.channelId as string, { amount, offset }); + if (olderMessages) { + olderMessages.reverse(); + console.log("older messages:", olderMessages); + if (olderMessages.length == 0) return; + for (const [i, oldMessage] of olderMessages.entries()) { + console.log("old message:", oldMessage); + messages.value.unshift(oldMessage); + for (const message of messages.value) { + groupMessage(message); + } + } + offset += offset; + } + } else { + fetched = false; + } + } + }); } }); diff --git a/components/Userpopup.vue b/components/Userpopup.vue index 1e90026..7381637 100644 --- a/components/Userpopup.vue +++ b/components/Userpopup.vue @@ -3,8 +3,12 @@ profile avatar
-

{{ props.user.display_name || "display_name" }}

-

{{ props.user.username || "username" }}

+

+ {{ props.user.display_name || "display_name" }} +

+

+ {{ props.user.username || "username" }} - {{ props.user.pronouns || "un/defined" }} +

About me
@@ -18,15 +22,15 @@ import type { UserResponse } from '~/types/interfaces'; const { fetchMembers } = useApi(); const props = defineProps<{ - user: UserResponse, + user: UserResponse | any, // actually UserResponse | null but TS is yelling at me again }>(); \ No newline at end of file diff --git a/components/buttons/Button.vue b/components/buttons/Button.vue index 20783c0..2544fbb 100644 --- a/components/buttons/Button.vue +++ b/components/buttons/Button.vue @@ -28,11 +28,11 @@ const props = defineProps<{ background-color: #b35719; color: #ffffff; - padding: 8px 16px; - font-size: 16px; + padding: 8px 18px; + font-size: 18px; transition: background-color 0.2s; - border-radius: 16px; + border-radius: 12px; text-decoration: none; display: inline-block; } diff --git a/components/buttons/ButtonScary.vue b/components/buttons/ButtonScary.vue index 71c0bc7..1fa2c85 100644 --- a/components/buttons/ButtonScary.vue +++ b/components/buttons/ButtonScary.vue @@ -28,11 +28,11 @@ const props = defineProps<{ background-color: #f02f2f; color: #ffffff; - padding: 8px 16px; - font-size: 16px; + padding: 8px 18px; + font-size: 18px; transition: background-color 0.2s; - border-radius: 16px; + border-radius: 12px; text-decoration: none; display: inline-block; } diff --git a/components/settings/user_settings/Account.vue b/components/settings/user_settings/Account.vue index 9b7d044..74d120d 100644 --- a/components/settings/user_settings/Account.vue +++ b/components/settings/user_settings/Account.vue @@ -2,10 +2,31 @@

My Account

-
- +
+
+

AVATAR

+ + +

DISPLAY NAME

+ +

USERNAME

+ +

PRONOUNS

+ +

ABOUT ME

+

{{ user?.about_me || "TBD" }}

+ + +
+
+ +
+
+
+
+

Password (and eventually authenticator)

@@ -19,10 +40,81 @@ import Button from '~/components/buttons/Button.vue'; import ButtonScary from '~/components/buttons/ButtonScary.vue'; -const { user, fetchUser } = useAuth(); +const { fetchUser } = useAuth(); const user_me = await fetchUser() +let user_reference = Object.assign({}, user_me) +const user = user_me! +let new_pfp_file: any = null + +const saveChanges = async () => { + try { + const formData = new FormData() + + if (new_pfp_file) { + formData.append('avatar', new_pfp_file, new_pfp_file.name) + new_pfp_file = null + } + + // oh lord praise deep seek v3 + const jsonBlob = new Blob( + [JSON.stringify({ + display_name: user.display_name, + username: user.username, + pronouns: user.pronouns, + })], + { type: 'application/json' } + ); + formData.append('json', jsonBlob, 'data.json'); + + await fetchWithApi("/me", { + method: "PATCH", + body: formData + }) + + user_reference = Object.assign({}, user_me) + alert("success!!") + } catch (error: any) { + if (error?.response?.status !== 200) { + const errorData = await error?.response?.json() + + alert(`error ${error?.response?.status} met whilst trying to update profile info\n${errorData}`) + } + } +}; + + +const removeAvatar = async () => { + alert("TBD") + // await fetchWithApi(`/auth/reset-password`); +} + +const changeAvatar = async () => { + try { + let input = document.createElement('input'); + input.type = 'file'; + input.accept = 'image/*'; + + input.onchange = async(e) => { + const file = e.target.files?.[0]; + if (!file) return; + + new_pfp_file = file; + + const reader = new FileReader(); + reader.onload = (e) => { + user.avatar = e?.target?.result; + }; + reader.readAsDataURL(file); + } + + input.oncancel = () => alert("cancelled upload!"); + input.click(); + } catch (err) { + console.error('User canceled or error:', err); + } +} const resetPassword = async () => { alert("TBD") @@ -35,11 +127,24 @@ const deleteAccount = async () => { \ No newline at end of file diff --git a/pages/settings.vue b/pages/settings.vue index 050c1f8..fb66aa2 100644 --- a/pages/settings.vue +++ b/pages/settings.vue @@ -115,8 +115,8 @@ const selectCategory = (_category: Category, page: Page) => { } #sidebar { - min-width: 200px; - max-width: 200px; + min-width: 250px; + max-width: 250px; background-color: #2f3136; color: white; padding: 10px; @@ -127,7 +127,7 @@ const selectCategory = (_category: Category, page: Page) => { } #sidebar h2 { - font-size: 1.5em; + font-size: 2em; padding: 0 8px; } @@ -140,6 +140,7 @@ const selectCategory = (_category: Category, page: Page) => { #sidebar li { border-radius: 8px; padding: 8px; + font-size: 1.3em; margin: 2px 0; cursor: pointer; transition: background-color 0.3s; @@ -155,7 +156,7 @@ const selectCategory = (_category: Category, page: Page) => { #sub_page { flex-grow: 1; - max-width: 600px; + max-width: 800px; margin-left: 1.5rem; margin-right: auto; diff --git a/public/favicon.ico b/public/favicon.ico index 18993ad..b3d28fa 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/types/interfaces.ts b/types/interfaces.ts index cd4b6dd..04da39a 100644 --- a/types/interfaces.ts +++ b/types/interfaces.ts @@ -59,6 +59,7 @@ export interface UserResponse { display_name: string | null, avatar: string | null, pronouns: string | null, + about_me: string | null, email?: string, email_verified?: boolean }