Skip to content

Commit 68d4bb7

Browse files
add badge and electrisity status
1 parent f0272e2 commit 68d4bb7

File tree

6 files changed

+132
-116
lines changed

6 files changed

+132
-116
lines changed

.github/workflows/publish.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ jobs:
6868
echo "DISCORD_GUILD_MEMBER_ROLE_ID=${{ vars.DISCORD_GUILD_MEMBER_ROLE_ID }}" >> ./envfile
6969
echo "DISCORD_GUILD_ID=${{ vars.DISCORD_GUILD_ID }}" >> ./envfile
7070
echo "JWT_SECRET=${{ secrets.JWT_SECRET }}" >> ./envfile
71+
echo "SPACE_ELECTRICITY_TRACKER_SLUG=${{ vars.SPACE_ELECTRICITY_TRACKER_SLUG }}" >> ./envfile
7172
7273
- name: Docker Stack Deploy
7374
uses: cssnr/stack-deploy-action@v1

app/components/Header.vue

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
11
<template>
22
<div class="container mx-auto px-4 py-4">
33
<div class="flex justify-between items-center">
4-
<NuxtLink
5-
to="/home"
6-
class="text-3xl font-bold text-accent-primary hover:opacity-80 transition-opacity"
7-
>
8-
NU31
9-
</NuxtLink>
104
<div class="flex items-center space-x-4">
11-
<NuxtLink
12-
v-if="isLoggedIn && avatarUrl"
13-
to="/profile"
14-
class="flex items-center space-x-3 hover:opacity-80 transition-opacity"
15-
>
16-
<img
17-
:src="avatarUrl"
18-
:alt="user?.name || 'User avatar'"
19-
class="w-10 h-10 rounded-full border-1 border-separator-primary"
20-
/>
5+
<NuxtLink to="/home" class="text-3xl font-bold text-accent-primary hover:opacity-80 transition-opacity">
6+
NU31
7+
</NuxtLink>
8+
<MainBadge v-if="!isLoading && status" :variant="badgeVariant" :label="badgeLabel" />
9+
</div>
10+
<div class="flex items-center space-x-4">
11+
<NuxtLink v-if="isLoggedIn && avatarUrl" to="/profile"
12+
class="flex items-center space-x-3 hover:opacity-80 transition-opacity">
13+
<img :src="avatarUrl" :alt="user?.name || 'User avatar'"
14+
class="w-10 h-10 rounded-full border-1 border-separator-primary" />
2115
<span class="text-sm font-medium text-label-primary">
2216
{{ user?.name }}
2317
</span>
@@ -31,10 +25,13 @@
3125
<script setup lang="ts">
3226
import { onMounted } from 'vue'
3327
import { useUser } from '~/composables/useUser'
28+
import { useElectricityStatus } from '~/composables/useElectricityStatus'
3429
3530
const { user, isLoggedIn, avatarUrl } = useUser()
31+
const { status, isLoading, badgeVariant, badgeLabel, fetchStatus } = useElectricityStatus()
3632
3733
onMounted(() => {
3834
useUser().fetchUser()
35+
fetchStatus()
3936
})
4037
</script>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { ref, computed } from 'vue'
2+
import { useRuntimeConfig } from '#imports'
3+
4+
type Status = 'online' | 'offline'
5+
6+
type ApiResponse = {
7+
current: { status: Status; lastAliveAt?: string; since?: string }
8+
}
9+
10+
const status = ref<Status | null>(null)
11+
const isLoading = ref(false)
12+
13+
export const useElectricityStatus = () => {
14+
const config = useRuntimeConfig()
15+
const slug = config.public.spaceElectricityTrackerSlug as string
16+
17+
const fetchStatus = async () => {
18+
isLoading.value = true
19+
try {
20+
const response = await $fetch<ApiResponse>(
21+
`/api/electricty_tracker/${slug}/history`
22+
)
23+
if (response?.current?.status) {
24+
status.value = response.current.status
25+
} else {
26+
status.value = 'offline'
27+
}
28+
} catch (error) {
29+
console.error('Failed to fetch electricity status:', error)
30+
status.value = 'offline'
31+
} finally {
32+
isLoading.value = false
33+
}
34+
}
35+
36+
const badgeVariant = computed(() => {
37+
if (status.value === 'online') {
38+
return 'success'
39+
}
40+
return 'error'
41+
})
42+
43+
const badgeLabel = computed(() => {
44+
if (status.value === 'online') {
45+
return 'світло є'
46+
}
47+
return 'світла немає'
48+
})
49+
50+
return {
51+
status,
52+
isLoading,
53+
badgeVariant,
54+
badgeLabel,
55+
fetchStatus,
56+
}
57+
}
58+

app/pages/index.vue

Lines changed: 58 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
11
<template>
22
<div class="min-h-screen bg-background-primary text-label-primary">
33
<div class="container mx-auto px-4 py-4">
4-
<div class="flex justify-end space-x-4 items-center">
5-
<MainButton
6-
buttonStyle="primary"
7-
size="M"
8-
icon="ic:baseline-discord"
9-
label="Вхід для резедентів"
10-
:link="data?.redirectUri"
11-
/>
12-
<ThemeSwitch />
4+
<div class="flex items-center justify-between">
5+
<div>
6+
<MainBadge v-if="!electricityLoading && electricityStatus" :variant="electricityBadgeVariant"
7+
:label="electricityBadgeLabel" />
8+
</div>
9+
<div class="flex items-center space-x-4">
10+
<MainButton buttonStyle="primary" size="M" icon="ic:baseline-discord" label="Вхід для резедентів"
11+
:link="data?.redirectUri" />
12+
<ThemeSwitch />
13+
</div>
1314
</div>
1415
</div>
1516

1617
<div class="relative w-full">
1718
<div class="w-full h-full"></div>
1819
<div class="w-full aspect-[1920/1080] relative">
19-
<div
20-
class="w-full h-full absolute inset-0 z-20 flex items-center text-center justify-center"
21-
>
20+
<div class="w-full h-full absolute inset-0 z-20 flex items-center text-center justify-center">
2221
<span class="text-8xl font-wallpoet text-accent-primary">
2322
NU31 Hacker Space
2423
</span>
@@ -42,27 +41,14 @@
4241
</p>
4342
</div>
4443

45-
<div
46-
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mb-20"
47-
>
48-
<div
49-
class="bg-fill-secondary p-8 rounded-xl border border-separator-primary"
50-
>
51-
<div
52-
class="w-16 h-16 bg-accent-primary rounded-full flex items-center justify-center mb-6 mx-auto"
53-
>
54-
<svg
55-
class="w-8 h-8 text-background-primary"
56-
fill="none"
57-
stroke="currentColor"
58-
viewBox="0 0 24 24"
59-
>
60-
<path
61-
stroke-linecap="round"
62-
stroke-linejoin="round"
63-
stroke-width="2"
64-
d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"
65-
></path>
44+
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mb-20">
45+
<div class="bg-fill-secondary p-8 rounded-xl border border-separator-primary">
46+
<div class="w-16 h-16 bg-accent-primary rounded-full flex items-center justify-center mb-6 mx-auto">
47+
<svg class="w-8 h-8 text-background-primary" fill="none" stroke="currentColor"
48+
viewBox="0 0 24 24">
49+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
50+
d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z">
51+
</path>
6652
</svg>
6753
</div>
6854
<h3 class="text-xl font-semibold mb-4 text-center">
@@ -74,24 +60,14 @@
7460
</p>
7561
</div>
7662

77-
<div
78-
class="bg-fill-tertiary p-8 rounded-xl border border-separator-secondary"
79-
>
63+
<div class="bg-fill-tertiary p-8 rounded-xl border border-separator-secondary">
8064
<div
81-
class="w-16 h-16 bg-accent-secondary rounded-full flex items-center justify-center mb-6 mx-auto"
82-
>
83-
<svg
84-
class="w-8 h-8 text-background-primary"
85-
fill="none"
86-
stroke="currentColor"
87-
viewBox="0 0 24 24"
88-
>
89-
<path
90-
stroke-linecap="round"
91-
stroke-linejoin="round"
92-
stroke-width="2"
93-
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.246 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"
94-
></path>
65+
class="w-16 h-16 bg-accent-secondary rounded-full flex items-center justify-center mb-6 mx-auto">
66+
<svg class="w-8 h-8 text-background-primary" fill="none" stroke="currentColor"
67+
viewBox="0 0 24 24">
68+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
69+
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.246 18 16.5 18c-1.746 0-3.332.477-4.5 1.253">
70+
</path>
9571
</svg>
9672
</div>
9773
<h3 class="text-xl font-semibold mb-4 text-center">
@@ -103,24 +79,13 @@
10379
</p>
10480
</div>
10581

106-
<div
107-
class="bg-fill-secondary p-8 rounded-xl border border-separator-primary"
108-
>
109-
<div
110-
class="w-16 h-16 bg-accent-primary rounded-full flex items-center justify-center mb-6 mx-auto"
111-
>
112-
<svg
113-
class="w-8 h-8 text-background-primary"
114-
fill="none"
115-
stroke="currentColor"
116-
viewBox="0 0 24 24"
117-
>
118-
<path
119-
stroke-linecap="round"
120-
stroke-linejoin="round"
121-
stroke-width="2"
122-
d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"
123-
></path>
82+
<div class="bg-fill-secondary p-8 rounded-xl border border-separator-primary">
83+
<div class="w-16 h-16 bg-accent-primary rounded-full flex items-center justify-center mb-6 mx-auto">
84+
<svg class="w-8 h-8 text-background-primary" fill="none" stroke="currentColor"
85+
viewBox="0 0 24 24">
86+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
87+
d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z">
88+
</path>
12489
</svg>
12590
</div>
12691
<h3 class="text-xl font-semibold mb-4 text-center">
@@ -140,13 +105,8 @@
140105
<p class="text-xl text-label-secondary mb-8">
141106
Знаходимося в серці Києва, Україна
142107
</p>
143-
<MainButton
144-
class="justify-center"
145-
buttonStyle="primary"
146-
size="M"
147-
link="https://discord.gg/kgTHaaHWyD"
148-
icon="ic:baseline-discord"
149-
>
108+
<MainButton class="justify-center" buttonStyle="primary" size="M" link="https://discord.gg/kgTHaaHWyD"
109+
icon="ic:baseline-discord">
150110
Ми тусимо в Discord, приєднуйся!
151111
</MainButton>
152112
</div>
@@ -169,24 +129,12 @@
169129
Соціальні мережі
170130
</h3>
171131
<div class="flex">
172-
<MainButton
173-
buttonStyle="ghost"
174-
size="L"
175-
link="https://github.com/nu31hackerspace"
176-
icon="mdi:github"
177-
></MainButton>
178-
<MainButton
179-
buttonStyle="ghost"
180-
size="L"
181-
link="https://www.instagram.com/nu31hackerspace/"
182-
icon="mdi:instagram"
183-
></MainButton>
184-
<MainButton
185-
buttonStyle="ghost"
186-
size="L"
187-
link="https://discord.gg/kgTHaaHWyD"
188-
icon="ic:baseline-discord"
189-
></MainButton>
132+
<MainButton buttonStyle="ghost" size="L" link="https://github.com/nu31hackerspace"
133+
icon="mdi:github"></MainButton>
134+
<MainButton buttonStyle="ghost" size="L" link="https://www.instagram.com/nu31hackerspace/"
135+
icon="mdi:instagram"></MainButton>
136+
<MainButton buttonStyle="ghost" size="L" link="https://discord.gg/kgTHaaHWyD"
137+
icon="ic:baseline-discord"></MainButton>
190138
</div>
191139
</div>
192140
</div>
@@ -199,11 +147,26 @@
199147
import { definePageMeta, navigateTo } from '#imports'
200148
import { onMounted } from 'vue'
201149
import { trackEvent } from '~~/app/utils/track'
150+
import { useFetch } from '#imports'
151+
import { useUser } from '~/composables/useUser'
152+
import { useElectricityStatus } from '~/composables/useElectricityStatus'
202153
203154
definePageMeta({
204155
layout: 'void',
205156
})
206157
158+
const { data } = await useFetch<{ redirectUri: string }>(
159+
'/api/auth/discord/redirect'
160+
)
161+
162+
const {
163+
status: electricityStatus,
164+
isLoading: electricityLoading,
165+
badgeVariant: electricityBadgeVariant,
166+
badgeLabel: electricityBadgeLabel,
167+
fetchStatus: fetchElectricityStatus,
168+
} = useElectricityStatus()
169+
207170
onMounted(async () => {
208171
trackEvent('page_view', { page: 'landing' })
209172
@@ -213,12 +176,7 @@ onMounted(async () => {
213176
console.log('isLoggedIn', isLoggedIn)
214177
navigateTo('/home')
215178
}
216-
})
217-
218-
import { useFetch } from '#imports'
219-
import { useUser } from '~/composables/useUser'
220179
221-
const { data } = await useFetch<{ redirectUri: string }>(
222-
'/api/auth/discord/redirect'
223-
)
180+
fetchElectricityStatus()
181+
})
224182
</script>

docker-stack.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ services:
1313
- NUXT_PUBLIC_DISCORD_CLIENT_ID=${DISCORD_CLIENT_ID}
1414
- NUXT_PUBLIC_DISCORD_GUILD_ID=${DISCORD_GUILD_ID}
1515
- NUXT_PUBLIC_DISCORD_GUILD_MEMBER_ROLE_ID=${DISCORD_GUILD_MEMBER_ROLE_ID}
16+
- NUXT_PUBLIC_SPACE_ELECTRICITY_TRACKER_SLUG=${SPACE_ELECTRICITY_TRACKER_SLUG}
1617
- NUXT_DISCORD_CLIENT_SECRET=${DISCORD_CLIENT_SECRET}
1718
- NUXT_DISCORD_BOT_TOKEN=${DISCORD_BOT_TOKEN}
1819
- NUXT_JWT_SECRET=${JWT_SECRET}

nuxt.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default defineNuxtConfig({
1818
discordClientId: '1418277247005229096',
1919
discordGuildId: '1279831505492901910',
2020
discordGuildMemberRoleId: '1280504520018755594',
21+
spaceElectricityTrackerSlug: 'nu31',
2122
},
2223
},
2324
vite: {

0 commit comments

Comments
 (0)