Skip to content

Commit

Permalink
support telegram announcements
Browse files Browse the repository at this point in the history
  • Loading branch information
dxstiny committed Jun 23, 2024
1 parent 6ac2c82 commit 7765c75
Show file tree
Hide file tree
Showing 3 changed files with 324 additions and 118 deletions.
19 changes: 13 additions & 6 deletions ui/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export interface IStudentStats {
discord: {
students: number;
graduates: number;
}
};
}

export interface IDegreeProgramme {
Expand All @@ -41,8 +41,8 @@ export interface IDegreeProgramme {
}

type AnnouncementScope = "discord" | "telegram";
export const ANNOUNCEMENT_TYPES = ["stair", "non-stair", "server", "test"]
type AnnouncementType = typeof ANNOUNCEMENT_TYPES[number];
export const ANNOUNCEMENT_TYPES = ["stair", "non-stair", "server", "test"];
type AnnouncementType = (typeof ANNOUNCEMENT_TYPES)[number];

const toBase64 = async (file?: File): Promise<string | undefined> => {
if (!file) {
Expand Down Expand Up @@ -131,6 +131,11 @@ export const api = {
res.json()
);
},
async telegramChats(): Promise<IServer[]> {
return fetch(`/api/announcements/telegram/chats`).then((res) =>
res.json()
);
},
async personas(): Promise<string[]> {
return fetch(`/api/announcements/personas`).then((res) =>
res.json()
Expand Down Expand Up @@ -162,14 +167,16 @@ export const api = {
async getDegreeProgrammes(): Promise<IDegreeProgramme[]> {
return fetch("/api/degree-programmes").then((res) => res.json());
},
async updateDegreeProgrammes(degreeProgrammes: IDegreeProgramme[]): Promise<void> {
async updateDegreeProgrammes(
degreeProgrammes: IDegreeProgramme[]
): Promise<void> {
await fetch("/api/degree-programmes", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(degreeProgrammes),
});
}
}
},
},
};
197 changes: 197 additions & 0 deletions ui/src/views/Announcements/EditorView/Telegram.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
<script setup lang="ts">
import { computed, watch, ref, type PropType, onMounted } from "vue";
import {
api,
ANNOUNCEMENT_TYPES,
type IServer,
type IAnnouncement,
} from "@/api";
import {
DiscordMarkdown,
DiscordEmbed,
DiscordMention,
DiscordEmbedField,
DiscordMessage,
DiscordMessages,
// @ts-ignore
} from "@discord-message-components/vue";
const servers = ref<IServer[]>([]);
const server = ref<string>("");
const props = defineProps({
modelValue: { type: Object as PropType<IAnnouncement>, required: true },
});
const announcement = computed(() => ({ ...props.modelValue }));
const img = ref<File | null>(null);
const imgUrl = ref<string | null>(null);
onMounted(async () => {
servers.value = await api.announements.telegramChats();
server.value = servers.value[0].id;
});
watch(
() => img.value,
async (value) => {
if (value) {
imgUrl.value = URL.createObjectURL(value);
} else {
imgUrl.value = null;
}
}
);
const postAnnouncement = async () => {
await api.announements.publish(
announcement.value.id!,
"telegram",
String(servers.value[0].id),
"",
"",
img.value ?? undefined
);
};
const actionsDisabled = computed(() => {
return false;
});
const setImage = () => {
const input = document.createElement("input");
input.type = "file";
input.accept = "image/*";
input.onchange = (e) => {
const files = (e.target as HTMLInputElement).files;
if (files && files.length > 0) {
img.value = files[0];
}
};
input.click();
};
</script>

<template>
<div class="inputs">
<div class="dropdown">
<label>In Channel</label>
<select v-model="server">
<option
v-for="s in servers"
:key="s.id"
:value="s.id"
>
{{ s.name }}
</option>
</select>
</div>
<button
@click="setImage"
class="align-right secondary"
>
Set Image
</button>
</div>
<div>
<DiscordMessages>
<DiscordMessage
:bot="true"
role-color="green"
>
<DiscordMarkdown>
<DiscordMention type="Announcements" />
</DiscordMarkdown>
<img
v-if="imgUrl"
:src="imgUrl"
draggable="false"
/>
<DiscordEmbed>
<DiscordEmbedField color="#0b6a5c">
<DiscordMarkdown>
<img
src="https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/svg/1f1e9-1f1ea.svg"
alt="🇩🇪"
title="flag_de"
draggable="false"
class="flag"
/>
**{{ announcement.title }}**
<br />
{{ announcement.message.de }}
</DiscordMarkdown>
</DiscordEmbedField>
</DiscordEmbed>
<DiscordEmbed>
<DiscordEmbedField color="#0b6a5c">
<DiscordMarkdown
><img
src="https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/svg/1f1ec-1f1e7.svg"
alt="🇬🇧"
title="flag_gb"
draggable="false"
class="flag"
/>
**{{ announcement.title }}**
<br />
{{ announcement.message.en }}
</DiscordMarkdown>
</DiscordEmbedField>
</DiscordEmbed>
</DiscordMessage>
</DiscordMessages>
</div>

<div class="actions">
<button
@click="postAnnouncement"
class="danger"
:disabled="actionsDisabled"
>
Publish
</button>
</div>
</template>

<style scoped>
.flag {
width: 2ch;
transform: translateY(0.25em);
}
img:not(.flag) {
max-width: 75ch;
border-radius: 0.5em;
display: block;
z-index: -1;
}
.inputs {
display: flex;
gap: 1em;
align-items: center;
}
.align-right {
margin-left: auto;
}
.dropdown {
display: flex;
flex-direction: column;
gap: 0.5em;
}
</style>

<style>
.discord-messages {
border-radius: 0.5em;
box-shadow: 0 0 20px 10px rgba(0, 0, 0, 0.15);
}
.discord-embed .discord-embed-left-border {
background-color: #0b6a5c;
}
</style>
Loading

0 comments on commit 7765c75

Please sign in to comment.