Skip to content

Commit 73fb9a2

Browse files
authored
Merge pull request #14 from profcomff/feat/achievements
achievements mvp
2 parents 8625bcf + ab529bb commit 73fb9a2

27 files changed

Lines changed: 828 additions & 112 deletions

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"eslint-plugin-vue": "^9.32.0",
4040
"knip": "^5.45.0",
4141
"openapi-typescript": "^7.6.1",
42+
"postcss-html": "^1.8.0",
4243
"postcss-preset-env": "^10.1.5",
4344
"prettier": "^3.5.2",
4445
"stylelint": "^16.15.0",
@@ -53,6 +54,6 @@
5354
"vite-plugin-vuetify": "^2.1.0",
5455
"vite-svg-loader": "^5.1.0",
5556
"vue-tsc": "^2.2.6",
56-
"vuetify": "^3.7.14"
57+
"vuetify": "^3.9.5"
5758
}
5859
}

pnpm-lock.yaml

Lines changed: 27 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/App.vue

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,29 @@
11
<script setup lang="ts">
2-
import { useProfileStore } from './store';
2+
import { useProfileStore, useToastStore } from './store';
33
import { onMounted } from 'vue';
44
55
const profileStore = useProfileStore();
6+
const toastStore = useToastStore();
67
78
onMounted(() => {
8-
profileStore.fromUrl();
9+
profileStore.setupAdminSession(null);
910
});
1011
</script>
1112

1213
<template>
13-
<main class="container">
14-
<RouterView />
15-
</main>
16-
<footer>
17-
Made by
18-
<a href="https://app.profcomff.com"><img src="https://app.profcomff.com/favicon.png" class="logo" /></a>
19-
in association with
20-
<a href="https://dyakov.space"><img src="https://dyakov.space/files/Icon.svg" class="logo" /></a>
21-
</footer>
14+
<v-app class="container">
15+
<main class="main">
16+
<Suspense>
17+
<RouterView />
18+
</Suspense>
19+
</main>
20+
<v-snackbar-queue v-model="toastStore.queue"></v-snackbar-queue>
21+
</v-app>
2222
</template>
2323

2424
<style scoped>
2525
.container {
2626
width: 100%;
2727
height: 100%;
2828
}
29-
30-
footer {
31-
position: sticky;
32-
bottom: 0;
33-
width: 100%;
34-
color: gray;
35-
text-align: center;
36-
37-
& .logo {
38-
height: 30px;
39-
vertical-align: middle;
40-
}
41-
}
4229
</style>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<script setup lang="ts">
2+
import { useAchievementStore } from '@/store';
3+
import { ref } from 'vue';
4+
5+
const achievementStore = useAchievementStore();
6+
7+
const name = ref('');
8+
const description = ref('');
9+
10+
async function createAchievement() {
11+
const pic = (document.getElementById('pic') as HTMLFormElement).files[0];
12+
await achievementStore.create(name.value, description.value, pic);
13+
}
14+
</script>
15+
16+
<template>
17+
<form id="form-create" action="submit">
18+
<p>
19+
<label for="name">Название</label>
20+
<input v-model="name" type="text" name="name" id="name" />
21+
</p>
22+
<p>
23+
<label for="description">Описание</label>
24+
<input v-model="description" type="text" name="description" id="description" />
25+
</p>
26+
<p>
27+
<label for="photo">Иконка</label>
28+
<input type="file" name="picture_file" id="pic" />
29+
</p>
30+
<v-btn @click="createAchievement">Создать</v-btn>
31+
</form>
32+
</template>
33+
34+
<style lang="css" scoped></style>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<script setup lang="ts">
2+
import { router } from '@/router';
3+
import { useAchievementStore } from '@/store';
4+
import { Ref } from 'vue';
5+
6+
const props = defineProps({
7+
id: { type: Number, required: true },
8+
});
9+
const achievementStore = useAchievementStore();
10+
11+
async function confirmDeletion(isActive: Ref<boolean>) {
12+
await achievementStore.deleteAchievement(props.id);
13+
14+
isActive.value = false;
15+
router.push('/achievements');
16+
}
17+
18+
async function dismissDeletion(isActive: Ref<boolean>) {
19+
isActive.value = false;
20+
}
21+
</script>
22+
23+
<template>
24+
<v-dialog>
25+
<template #activator="{ props: activatorProps }">
26+
<v-btn v-bind="activatorProps" color="secondary">Удалить</v-btn>
27+
</template>
28+
29+
<template #default="{ isActive }">
30+
<h1>Удалить {{ id }}?</h1>
31+
<p>
32+
<v-btn @click="dismissDeletion(isActive)">Нет</v-btn>
33+
<v-btn @click="confirmDeletion(isActive)">Да</v-btn>
34+
</p>
35+
</template>
36+
</v-dialog>
37+
</template>
38+
39+
<style lang="css" scoped></style>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<script setup lang="ts">
2+
import { useAchievementStore } from '@/store';
3+
import { ref } from 'vue';
4+
5+
defineProps({
6+
id: { type: Number, required: true },
7+
});
8+
9+
const achievementStore = useAchievementStore();
10+
11+
const newName = ref('');
12+
const newDescription = ref('');
13+
</script>
14+
15+
<template>
16+
<form id="achievement-info" @submit.prevent>
17+
<h2>Изменить достижение</h2>
18+
19+
<p>
20+
<label for="name">Название</label>
21+
<input v-model="newName" name="name" id="name" />
22+
</p>
23+
24+
<p>
25+
<label for="description">Описание</label>
26+
<input v-model="newDescription" name="description" id="description" />
27+
</p>
28+
<v-btn @click="achievementStore.edit(id, newName, newDescription)">Изменить</v-btn>
29+
</form>
30+
</template>
31+
32+
<style lang="css" scoped></style>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<script setup lang="ts">
2+
import { useAchievementStore } from '@/store';
3+
import { ref, onMounted, onUpdated } from 'vue';
4+
5+
const props = defineProps<{
6+
definedAchievement?: number;
7+
definedReceiver?: number;
8+
}>();
9+
10+
const achievementId = ref(0);
11+
const receiverId = ref(0);
12+
13+
onMounted(() => {
14+
achievementId.value = props.definedAchievement ?? 0;
15+
receiverId.value = props.definedReceiver ?? 0;
16+
});
17+
18+
onUpdated(() => {
19+
if (props.definedAchievement) {
20+
achievementId.value = props.definedAchievement;
21+
}
22+
if (props.definedReceiver) {
23+
receiverId.value = props.definedReceiver;
24+
}
25+
});
26+
27+
const achievementStore = useAchievementStore();
28+
</script>
29+
30+
<template>
31+
<form action="submit">
32+
<p>
33+
<label for="achievement-id">Номер достижения</label>
34+
<input
35+
v-model="achievementId"
36+
type="number"
37+
name="achievement_id"
38+
id="achievement-id"
39+
:disabled="!!definedAchievement"
40+
/>
41+
</p>
42+
<p>
43+
<label for="user-id">User id</label>
44+
<input v-model="receiverId" type="number" name="user_id" id="user-id" :disabled="!!definedReceiver" />
45+
</p>
46+
<v-btn @click="achievementStore.createReceiver(achievementId, receiverId)">Выдать</v-btn>
47+
</form>
48+
</template>
49+
50+
<style lang="css" scoped></style>

0 commit comments

Comments
 (0)