import './Announcement.js' import server from '../../_/code/bridge/server.js' import '../../components/SearchBar.js' css(` announcements- { font-family: 'Arial'; scrollbar-width: none; -ms-overflow-style: none; } announcements- h1 { font-family: 'Bona'; } announcements- .VStack::-webkit-scrollbar { display: none; width: 0px; height: 0px; } announcements- .VStack::-webkit-scrollbar-thumb { background: transparent; } announcements- .VStack::-webkit-scrollbar-track { background: transparent; } `) class Announcements extends Shadow { static searchableKeys = ['message', 'author']; constructor() { super() this.announcements = global.currentNetwork.data.announcements.sort((a, b) => new Date(b.created) - new Date(a.created)); this.searchedAnnouncements = []; this.searchText = ""; } render() { ZStack(() => { VStack(() => { SearchBar(this.searchText, "90vw") VStack(() => { if (!this.announcements || this.announcements == []) { LoadingCircle() } else if (this.searchText) { if (this.searchedAnnouncements.length > 0) { for (let i = 0; i < this.searchedAnnouncements.length; i++) { AnnouncementCard(this.searchedAnnouncements[i]) } } else { h2("Could not find any announcements with your search criteria.") .color("var(--divider)") .fontWeight("bold") .marginTop(7.5, em) .marginBottom(0.5, em) .textAlign("center") } } else if (this.announcements.length > 0) { for (let i = 0; i < this.announcements.length; i++) { AnnouncementCard(this.announcements[i]) } } else { h2("No Announcements") .color("var(--divider)") .fontWeight("bold") .marginTop(7.5, em) .marginBottom(0.5, em) .textAlign("center") } }) .overflowY("scroll") .gap(0.75, em) if(global.currentNetwork.permissions.includes("announcements.add")) { HStack(() => { input("Image Upload", "0px", "0px") .attr({ name: "image-upload", type: "file" }) .display("none") .visibility("hidden") .onChange((e) => { const file = e.target.files[0] if (!file) return this.stagedImage = file this.stagedImageURL = URL.createObjectURL(file) this.rerender() }) div("+") .width(3, rem) .height(3, rem) .borderRadius(50, pct) .border("1px solid color-mix(in srgb, var(--accent) 60%, transparent)") .fontSize(2, em) .transform("rotate(180deg)") .zIndex(1001) .display("flex") .alignItems("center") .justifyContent("center") .transition("scale .2s") .state("touched", function (touched) { if(touched) { this.scale("1.5") this.color("var(--darkaccent)") this.backgroundColor("var(--divider)") } else { this.scale("") this.color("var(--divider)") this.backgroundColor("var(--searchbackground)") } }) .onTouch(function (start) { if(start) { this.attr({touched: "true"}) } else { this.attr({touched: ""}) } }) .onClick((done) => { if(done) { const inputSelector = this.$('[name="image-upload"]'); inputSelector.click() } }) input("Add an Announcement") .flex("1 1 auto") .minWidth(0) .color("var(--text)") .background("var(--searchbackground)") .paddingVertical(0, rem) .fontSize(1, rem) .paddingHorizontal(1, rem) .borderRadius(100, px) .border("1px solid color-mix(in srgb, var(--accent) 60%, transparent)") .onTouch(function (start) { if (start) { this.style.backgroundColor = "var(--accent)" } else { setTimeout(() => { $("appmenu-").display("none") this.focus() }, 20) console.log($("appmenu-")) this.style.backgroundColor = "var(--searchbackground)" } }) .addEventListener("blur", () => { setTimeout(() => { $("appmenu-").display("grid") }, 20) }) }) .width(100, pct) .boxSizing("border-box") .position("absolute") .paddingHorizontal(1, rem) .bottom(1, vh) .gap(0.5, rem) } }) .boxSizing("border-box") .height(100, pct) .width(100, pct) .onEvent("announcementsearch", this.onAnnouncementSearch) .onEvent("new-announcement", this.onNewAnnouncement) .onEvent("deleted-announcement", this.onDeletedAnnouncement) .onEvent("edited-announcement", this.onEditedAnnouncement) }) } async handleUpload(file) { try { const body = new FormData(); body.append('image', file); const res = await util.authFetch(`${util.HOST}/profile/upload-image`, { method: "POST", credentials: "include", headers: { "Accept": "application/json" }, body: body }); if(res.status === 401) { return res.status } if (!res.ok) return res.status; const data = await res.json() global.profile = data.member console.log(global.profile) } catch (err) { // Network error / Error reaching server console.error(err); } } addPhoto() { console.log("hey") } onNewAnnouncement = (e) => { let newAnnouncement = e.detail.announcement; this.announcements.push(newAnnouncement) this.announcements.sort((a, b) => new Date(b.created) - new Date(a.created)); this.rerender() } onDeletedAnnouncement = (e) => { let deletedId = e.detail.id const i = this.announcements.findIndex(ann => ann.id === deletedId) if (i !== -1) this.announcements.splice(i, 1); this.rerender() } onEditedAnnouncement = (e) => { let editedAnnouncement = e.detail const i = this.announcements.findIndex(ann => ann.id === editedAnnouncement.id) if (i !== -1) { this.announcements.splice(i, 1) this.announcements.unshift(editedAnnouncement) } this.rerender() } onAnnouncementSearch = (e) => { let searchText = e.detail.searchText.toLowerCase().trim(); if (!searchText) { this.searchedAnnouncements = []; } else { this.searchedAnnouncements = this.announcements.filter(announcement => Announcements.searchableKeys.some(key => String(announcement[key]).toLowerCase().includes(searchText) ) ); } this.searchText = searchText this.rerender() } async getAnnouncements(networkId) { const fetchedAnnouncements = await server.getAnnouncements(networkId) if (this.checkForUpdates(this.announcements, fetchedAnnouncements.data)) { this.announcements = fetchedAnnouncements.data.sort((a, b) => new Date(b.created) - new Date(a.created)); global.currentNetwork.data.announcements = this.announcements this.rerender() } } connectedCallback() { this.getAnnouncements(global.currentNetwork.id) } checkForUpdates(currentAnnouncements, fetchedAnnouncements) { if (currentAnnouncements.length !== fetchedAnnouncements.length) return true; const currentMap = new Map(currentAnnouncements.map(ann => [ann.id, ann])); for (const fetchedAnn of fetchedAnnouncements) { const currentAnn = currentMap.get(fetchedAnn.id); if (!currentAnn) return true; if (currentAnn.updated_at !== fetchedAnn.updated_at) return true; } return false; } } register(Announcements)