Skip to content

Commit

Permalink
feat: replace -1 quota in homeworks and problems with unlimited l… (
Browse files Browse the repository at this point in the history
#139)

* feat: replace `-1` quota in homeworks and problems with `unlimited` literal

not transforming `-1` quota into `-` string, only control the appearence in UI

* refactor: extract unlimited quota `-1` constant and provide checker function
  • Loading branch information
uier authored Jul 27, 2023
1 parent 8fcf4d2 commit 72dabf5
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 34 deletions.
7 changes: 6 additions & 1 deletion src/components/Homework/HomeworkCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import { computed } from "vue";
import { useSession } from "@/stores/session";
import { formatTime } from "@/utils/formatTime";
import { useI18n } from "vue-i18n";
import type { ProblemId2Meta } from "@/composables/useProblemSelection";
import { isQuotaUnlimited } from "@/constants";
const { t } = useI18n();
interface Props {
homework: HomeworkListItem | HomeworkPreviewForm;
problems: Record<string, { name: string | "-"; quota: number | "-" }>;
problems: ProblemId2Meta;
preview?: boolean;
}
Expand Down Expand Up @@ -101,6 +103,9 @@ const state = computed(() => {
</td>
<td>
<ui-spinner v-if="!problems[pid.toString()]" />
<span v-else-if="isQuotaUnlimited(problems[pid.toString()].quota)" class="text-sm">{{
$t("components.problem.card.unlimited")
}}</span>
<span v-else>{{ problems[pid.toString()].quota }}</span>
</td>
<td>
Expand Down
10 changes: 8 additions & 2 deletions src/components/Problem/ProblemCard.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { useSession } from "@/stores/session";
import api from "@/models/api";
import { isQuotaUnlimited } from "@/constants";
interface Props {
problem: Problem;
Expand Down Expand Up @@ -36,8 +37,13 @@ function downloadTestCase(problemId: number) {
<div class="stat place-items-center py-0">
<div class="stat-title">{{ $t("components.problem.card.quota") }}</div>
<div class="stat-value">
<span>{{ problem.quota - problem.submitCount }}</span>
<span class="text-sm font-normal">{{ ` / ${problem.quota}` }}</span>
<template v-if="isQuotaUnlimited(problem.quota)">
<span class="text-sm">{{ $t("components.problem.card.unlimited") }}</span>
</template>
<template v-else>
<span>{{ problem.quota - problem.submitCount }}</span>
<span class="text-sm font-normal">{{ ` / ${problem.quota}` }}</span>
</template>
</div>
</div>
<div class="stat place-items-center py-0">
Expand Down
10 changes: 6 additions & 4 deletions src/composables/useProblemSelection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useAxios } from "@vueuse/integrations/useAxios";
import { fetcher } from "@/models/api";

type ProblemSelections = { value: string; text: string }[];
type ProblemId2Meta = Record<string, { name: string | "-"; quota: number | "-" }>;
export type ProblemId2Meta = Record<string, { name: string; quota: number }>;

export function useProblemSelection(courseName: string) {
const {
Expand All @@ -14,17 +14,19 @@ export function useProblemSelection(courseName: string) {

const problemSelections = computed<ProblemSelections>(() => {
if (!problems.value) return [];
return problems.value.map(({ problemId, problemName, quota }) => ({
return problems.value.map(({ problemId, problemName }) => ({
value: problemId.toString(),
text: `${problemId} - ${problemName}`,
quota: quota >= 0 ? quota : "-",
}));
});

const problemId2Meta = computed<ProblemId2Meta>(() => {
if (!problems.value) return {};
return Object.fromEntries(
problems.value.map((p) => [p.problemId.toString(), { name: p.problemName, quota: p.quota }]),
problems.value.map(({ problemId, problemName, quota }) => [
problemId.toString(),
{ name: problemName, quota },
]),
);
});

Expand Down
5 changes: 5 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,8 @@ export const LOCAL_STORAGE_KEY = {
LOCALE: "locale",
LAST_USED_LANG: "last-used-lang",
};

export const UNLIMITED_QUOTA = -1;
export function isQuotaUnlimited(quota: number): boolean {
return quota === UNLIMITED_QUOTA;
}
3 changes: 2 additions & 1 deletion src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,8 @@
"ml": "Memory Limit",
"score": "Score"
},
"noContent": "no content"
"noContent": "no content",
"unlimited": "unlimited"
}
},
"courseSideBar": {
Expand Down
3 changes: 2 additions & 1 deletion src/i18n/zh-tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,8 @@
"ml": "記憶體限制",
"score": "配分"
},
"noContent": ""
"noContent": "",
"unlimited": "無限制"
}
},
"courseSideBar": {
Expand Down
32 changes: 8 additions & 24 deletions src/pages/course/[name]/homeworks/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,22 @@ import { fetcher } from "@/models/api";
import { useSession } from "@/stores/session";
import { useTitle } from "@vueuse/core";
import { computed } from "vue";
import { useProblemSelection } from "@/composables/useProblemSelection";
const session = useSession();
const route = useRoute();
useTitle(`Homeworks - ${route.params.name} | Normal OJ`);
const { data, error, isLoading } = useAxios<HomeworkList>(`/course/${route.params.name}/homework`, fetcher);
const { data: problems, error: fetchProblemError } = useAxios<ProblemList>(
`/problem?offset=0&count=-1&course=${route.params.name}`,
fetcher,
);
const {
problemId2Meta,
error: fetchProblemError,
isLoading: isFetchingProblem,
} = useProblemSelection(route.params.name as string);
const homeworks = computed(() => {
if (!data.value) return [];
return data.value.sort((a, b) => b.start - a.start);
});
type ProblemMeta = Record<
string,
{
name: string;
quota: number | "-";
}
>;
function getProblemMeta(ids: number[]): ProblemMeta {
if (!problems.value) return {};
const _problems = problems.value;
return Object.fromEntries(
ids.map((pid) => {
const p = _problems.find((p) => p.problemId === pid);
return [pid, p ? { name: p.problemName, quota: p.quota } : { name: "-", quota: "-" }];
}),
);
}
</script>

<template>
Expand All @@ -53,7 +37,7 @@ function getProblemMeta(ids: number[]): ProblemMeta {
<i-uil-plus-circle class="mr-1 lg:h-5 lg:w-5" /> {{ $t("course.hw.index.new") }}
</router-link>
</div>
<data-status-wrapper :error="error || fetchProblemError" :is-loading="isLoading">
<data-status-wrapper :error="error || fetchProblemError" :is-loading="isLoading || isFetchingProblem">
<template #loading>
<skeleton-card />
</template>
Expand All @@ -62,7 +46,7 @@ function getProblemMeta(ids: number[]): ProblemMeta {
v-for="homework in homeworks"
:key="homework.id"
:homework="homework"
:problems="getProblemMeta(homework.problemIds)"
:problems="problemId2Meta"
class="mb-2"
/>
</template>
Expand Down
8 changes: 7 additions & 1 deletion src/pages/course/[name]/problems.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { computed, ref, watch, watchEffect } from "vue";
import { fetcher } from "@/models/api";
import { UserRole, useSession } from "@/stores/session";
import { useTitle } from "@vueuse/core";
import { isQuotaUnlimited } from "@/constants";
const session = useSession();
const rolesCanReadProblemStatus = [UserRole.Admin, UserRole.Teacher];
Expand Down Expand Up @@ -89,7 +90,12 @@ const maxPage = computed(() => {
<td>
<span class="badge badge-info mr-1" v-for="tag in tags" :key="tag">{{ tag }}</span>
</td>
<td>{{ quota - submitCount }} / {{ quota }}</td>
<td>
<template v-if="isQuotaUnlimited(quota)">
<span class="text-sm">{{ $t("components.problem.card.unlimited") }}</span>
</template>
<template v-else> {{ quota - submitCount }} / {{ quota }} </template>
</td>
<td>
<div class="tooltip" data-tip="Stats">
<router-link
Expand Down

0 comments on commit 72dabf5

Please sign in to comment.