Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 6 additions & 11 deletions components/challenges/MyRank.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
<template>
<article
class="flex items-center p-2 bg-error-light rounded-md md:rounded-lg"
>
<!-- bg-[#546bed2f] text-[#546bed] -->
<TrophyIcon class="w-5 h-5 md:w-6 md:h-6 flex-shrink-0 text-error" />
<h6 class="text-heading-4 ml-2 pr-1 md:ml-2.5">
{{ t('Headings.MyRank', { rank: ordinalRank }) }}
</h6>
</article>
<article class="flex items-center py-2 px-4 bg-error-light rounded-md md:rounded-lg">
<TrophyIcon class="w-5 h-5 md:w-6 md:h-6 flex-shrink-0 text-error" />
<h6 class="text-heading-4 ml-2 pr-1 md:ml-2.5">
{{ t('Headings.MyRank', { rank: ordinalRank }) }}
</h6>
</article>
</template>

<script lang="ts">
Expand Down Expand Up @@ -38,5 +35,3 @@ export default defineComponent({
},
});
</script>

<style scoped></style>
108 changes: 45 additions & 63 deletions components/challenges/Progress.vue
Original file line number Diff line number Diff line change
@@ -1,91 +1,73 @@
<template>
<article class="grid gap-2">
<!-- box style-box bg-secondary -->
<h3 class="text-body-1">{{ data?.heading }}</h3>
<p class="text-right">{{ value }} / {{ max }}</p>
<progress
:id="data?.heading"
:value="value"
:max="max"
class="w-full col-span-2"
:class="{ 'loading transition-basic animate-pulse': loading }"
></progress>
</article>
<article class="grid gap-2">
<h3 v-if="heading" class="text-body-1">{{ heading }}</h3>
<p class="text-right">{{ totalValue }} / {{ max }}</p>
<div class="progress-container w-full col-span-2">
<div v-for="(subdivision, index) in subdivisions" :key="index" :class="[subdivision.color]"
:style="{ width: getSubdivisionWidth(subdivision) }" class="progress-segment" />
<div v-if="remainingPercentage > 0" class="progress-segment bg-dark" :style="{ width: remainingPercentage }" />
</div>
</article>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent, computed } from 'vue';
import type { PropType } from 'vue';
import { useI18n } from 'vue-i18n';

interface PropData {
heading: string;
current: number;
total: number;
}

export default defineComponent({
props: {
data: { type: Object as PropType<PropData | null>, default: null },
loading: { type: Boolean, default: true },
heading: { type: String, default: '' },
subdivisions: { type: Array as PropType<{ value: number; color: string }[]>, required: true },
total: { type: Number, required: true },
},
setup(props) {
const { t } = useI18n();

const DEFAULT_MAX_VALUE = 10;
const subdivisions = computed(() => {
return props.subdivisions ?? [];
});

const value = computed(() => {
return props.data?.current ?? getRandomNumber(1, DEFAULT_MAX_VALUE - 1);
const totalValue = computed(() => {
return subdivisions.value.reduce((acc, subdivision) => acc + subdivision.value, 0);
});

const max = computed(() => {
return props.data?.total ?? DEFAULT_MAX_VALUE;
return props.total;
});

const getSubdivisionWidth = (subdivision: { value: number }) => {
const total = max.value;
return total > 0 ? `${(subdivision.value / total) * 100}%` : '0%';
};

const remainingPercentage = computed(() => {
const total = max.value;
const used = totalValue.value;
return total > 0 ? ((total - used) / total) * 100 : 0;
});

return { t, value, max };
return { t, subdivisions, totalValue, max, getSubdivisionWidth, remainingPercentage };
},
});
</script>

<style scoped>
progress {
background-color: var(--color-primary);
border-radius: 1rem;
-webkit-transition: all 0.5s ease-in-out;
-moz-transition: all 0.5s ease-in-out;
-o-transition: all 0.5s ease-in-out;
transition: all 0.5s ease-in-out;
.progress-container {
display: flex;
height: 1rem;
border-radius: 1rem;
overflow: hidden;
background-color: var(--color-primary);
transition: all 0.5s ease-in-out;
}
progress::-webkit-progress-bar {
background-color: var(--color-primary);
border-radius: 1rem;
-webkit-transition: all 0.5s ease-in-out;
-moz-transition: all 0.5s ease-in-out;
-o-transition: all 0.5s ease-in-out;
transition: all 0.5s ease-in-out;
}
progress::-webkit-progress-value {
background-color: var(--color-accent);
/* background-color: #546bed; */
border-radius: 1rem;
-webkit-transition: width 0.5s ease-in-out;
-moz-transition: width 0.5s ease-in-out;
-o-transition: width 0.5s ease-in-out;
transition: width 0.5s ease-in-out;
}
progress::-moz-progress-bar {
background-color: var(--color-accent);
/* background-color: #546bed; */
border-radius: 1rem;
-webkit-transition: width 0.5s ease-in-out;
-moz-transition: width 0.5s ease-in-out;
-o-transition: width 0.5s ease-in-out;
transition: width 0.5s ease-in-out;
}
progress.loading::-webkit-progress-value {
background-color: #2e405a;

.progress-segment {
height: 100%;
transition: width 0.5s ease-in-out;
}
progress.loading::-moz-progress-bar {
background-color: #2e405a;

.bg-dark {
background-color: var(--bg-dark);
}
</style>
37 changes: 7 additions & 30 deletions components/challenges/ProgressSummary.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
<template>
<section class="flex flex-wrap gap-x-container">
<article
@click="navigateTo('/challenges/all')"
v-for="({ label, value, border, text }, i) of summary"
:key="i"
class="text-center flex gap-box w-fit items-center cursor-pointer"
:class="[border]"
>
<p class="text-heading-2" :class="[text]">{{ value }}</p>
<section class="flex flex-wrap gap-12">
<article v-for="({ label, value, border, text }, i) of summary" :key="i"
class="text-center flex gap-2 w-fit items-center" :class="[border]">
<p class="text-body-1" :class="[text]">{{ value }}</p>
<h3 class="text-body-1">{{ t(label) }}</h3>
</article>
</section>
Expand All @@ -20,11 +15,7 @@ import { useI18n } from "vue-i18n";

interface PropData {
attempted: number;
locked: number;
solved: number;
total: number;
unattempted: number;
unlocked: number;
}

export default defineComponent({
Expand All @@ -38,9 +29,9 @@ export default defineComponent({
const summary = computed(() => {
return [
{
label: "Headings.Total",
value: props.data?.total ?? 0,
border: "border-[#f2c94c20]",
label: "Headings.Attempted",
value: props.data?.attempted ?? 0,
border: "border-[#eb585720]",
text: "text-warning",
},
{
Expand All @@ -49,24 +40,10 @@ export default defineComponent({
border: "border-[#00cc9920]",
text: "text-success",
},
{
label: "Headings.Unattempted",
value: props.data?.unattempted ?? 0,
border: "border-[#eb585720]",
text: "text-error",
},
{
label: "Headings.Attempted",
value: props.data?.attempted ?? 0,
border: "border-[#eb585720]",
text: "text-error",
},
];
});

return { t, summary };
},
});
</script>

<style scoped></style>
79 changes: 31 additions & 48 deletions components/user/Challenges.vue
Original file line number Diff line number Diff line change
@@ -1,74 +1,57 @@
<template>
<section class="bg-secondary card style-card grid gap-card-sm">
<div class="flex flex-wrap gap-box items-start justify-between mb-2">
<SectionTitle
sub
heading="Headings.MyChallengesStats"
body="Body.MyChallengesStats"
class="!m-0"
/>
<ChallengesMyRank :rank="myChallengesStats?.rank ?? 0" />
<div class="flex max-md:flex-wrap gap-box items-start justify-between mb-2">
<SectionTitle sub heading="Headings.MyChallengesStats" body="Body.MyChallengesStats" class="!m-0" />
<NuxtLink to="/challenges/leader-board" class="max-sm:hidden">
<Btn class="w-full justify-center" :icon="TrophyIcon">
{{ t("Buttons.GoToLeaderBoard") }}
</Btn>
</NuxtLink>
</div>

<ChallengesProgressSummary :data="codingChallengesStats ?? null" />
<ChallengesProgress v-if="progress.total != null" :heading="t('Headings.Progress')" :subdivisions="[
{ value: progress.attempted, color: 'bg-warning' },
{ value: progress.solved, color: 'bg-accent' },
]" :total="progress.total" />
<p v-else class="px-2 max-w-max rounded-md text-error border border-error">
{{ t("Headings.NoChallengesStats") }}
</p>

<ChallengesProgress
v-for="(item, i) of progress"
:key="i"
:data="item"
:loading="loading"
/>
<ChallengesProgressSummary :data="codingChallengesStats ?? null" />

<article class="flex flex-wrap gap-card-sm mt-4">
<!-- <NuxtLink to="/profile/challenges">
<Btn secondary>
{{ t('Buttons.MyChallenges') }}
</Btn>
</NuxtLink> -->
<NuxtLink to="/challenges/leader-board">
<Btn>
{{ t("Buttons.LeaderBoard") }}
</Btn>
</NuxtLink>
</article>
<NuxtLink to="/challenges/leader-board" class="sm:hidden mt-4">
<Btn class="w-full justify-center">
{{ t("Buttons.GoToLeaderBoard") }}
</Btn>
</NuxtLink>
</section>
</template>

<script lang="ts">
import { TrophyIcon } from "@heroicons/vue/24/outline";
import { defineComponent } from "vue";
import { useI18n } from "vue-i18n";

export default defineComponent({
components: { TrophyIcon },
setup() {
const { t } = useI18n();

const myChallengesStats = useMyChallengesStats();


const codingChallengesStats: any = useCodingChallengesStats();
const loading = ref(!!!codingChallengesStats.value);

onMounted(async () => {
await getCodingChallengesStats();
loading.value = false;
});
// const propgress = computed(() => {});

const progress = computed(() => {
return [
{
heading: t("Headings.Attempted"),
current: codingChallengesStats.value?.attempted ?? 0,
total: codingChallengesStats.value?.total ?? 10,
},
{
heading: t("Headings.ChallengesSolved"),
current: codingChallengesStats.value?.solved ?? 0,
total: codingChallengesStats.value?.total ?? 10,
},
];
return {
attempted: codingChallengesStats.value?.attempted ?? 0,
solved: codingChallengesStats.value?.solved ?? 0,
total: codingChallengesStats.value?.total,
};
});

return { t, loading, myChallengesStats, codingChallengesStats, progress };
return { t, codingChallengesStats, progress, TrophyIcon };
},
});
</script>

<style scoped></style>
7 changes: 4 additions & 3 deletions locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@
"EmptyLeaderBoardList": "Die Bestenliste ist leer. Besuche uns noch einmal.",
"ChangeEnvironment": "Umgebung ändern",
"LeaderBoard": "Bestenliste",
"Unattempted": "Unversucht",
"Progress": "Fortschritt",
"NoChallengesStats": "Keine Challenge-Statistiken verfügbar",
"Unlocked": "Entsperrt",
"Attempted": "Versucht",
"Feedback": "Rückmeldung",
Expand Down Expand Up @@ -174,13 +175,12 @@
"SolvedFirst": "Als Erster gelöst",
"Correct": "Korrekt",
"Score": "Punktzahl: {score}",
"ChallengesSolved": "Gelöste Challenges",
"CategoriesCompleted": "Abgeschlossene Kategorien",
"Solved": "Gelöst",
"Incorrect": "Falsch",
"Untried": "Unversucht",
"Locked": "Verschlossen",
"MyRank": "Mein Rang: {rank}",
"MyRank": "{rank} Rang",
"MyChallengesStats": "Meine Challenge-Statistiken",
"MultiChoice": "Multiple-Choice",
"SingleChoice": "Single-Choice",
Expand Down Expand Up @@ -811,6 +811,7 @@
"MyChallenges": "Meine Challenges",
"Challenges": "Challenges",
"LeaderBoard": "Bestenliste",
"GoToLeaderBoard": "Zur Bestenliste",
"CreateQuiz": "Quiz erstellen",
"CreateQuizQuestion": "Quizfrage erstellen",
"SubmitAnswer": "Antwort einreichen",
Expand Down
Loading