Skip to content

Commit

Permalink
Merge pull request #34 from Nauxscript/feature/progress-fe
Browse files Browse the repository at this point in the history
Feature/progress fe
  • Loading branch information
Nauxscript authored Jan 27, 2024
2 parents e555c56 + 694e8c0 commit baa7b95
Show file tree
Hide file tree
Showing 15 changed files with 257 additions and 40 deletions.
3 changes: 2 additions & 1 deletion apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
"class-validator": "^0.14.1",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1",
"start": "^5.1.0"
"start": "^5.1.0",
"superagent": "^8.1.2"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
Expand Down
2 changes: 2 additions & 0 deletions apps/api/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { UserModule } from '../user/user.module';
import { AuthModule } from '../auth/auth.module';
import { CourseModule } from '../course/course.module';
import { UserProgressModule } from '../user-progress/user-progress.module';
import { ToolModule } from 'src/tool/tool.module';

@Module({
imports: [
Expand All @@ -12,6 +13,7 @@ import { UserProgressModule } from '../user-progress/user-progress.module';
AuthModule,
CourseModule,
UserProgressModule,
ToolModule,
],
})
export class AppModule {}
12 changes: 12 additions & 0 deletions apps/api/src/tool/tool.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Controller, Get } from '@nestjs/common';
import { ToolService } from './tool.service';

@Controller('tool')
export class ToolController {
constructor(private readonly toolService: ToolService) {}

@Get('dailySentence')
dailySentence() {
return this.toolService.dailySentence();
}
}
9 changes: 9 additions & 0 deletions apps/api/src/tool/tool.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { ToolService } from './tool.service';
import { ToolController } from './tool.controller';

@Module({
controllers: [ToolController],
providers: [ToolService],
})
export class ToolModule {}
17 changes: 17 additions & 0 deletions apps/api/src/tool/tool.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Injectable } from '@nestjs/common';
import * as superagent from 'superagent';

@Injectable()
export class ToolService {
async dailySentence() {
const { text } = await superagent.get(
'https://open.iciba.com/dsapi/?date=2023-05-03',
);
const data = JSON.parse(text);
const res = {
zh: data.note,
en: data.content,
};
return res;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@ export class CreateUserProgressDto {
@IsNotEmpty({ message: '课程不能为空' })
courseId: number;
}

export class UpdateUserProgressDto {
@ApiProperty()
@IsNotEmpty({ message: '课程不能为空' })
courseId: number;
}
12 changes: 7 additions & 5 deletions apps/api/src/user-progress/user-progress.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import {
Request,
Get,
Put,
Param,
} from '@nestjs/common';
import { UserProgressService } from './user-progress.service';
import { AuthGuard } from '../auth/auth.guard';
import { CreateUserProgressDto } from './model/update-user-progress.dto';
import {
CreateUserProgressDto,
UpdateUserProgressDto,
} from './model/user-progress.dto';

@Controller('user-progress')
export class UserProgressController {
Expand All @@ -29,8 +31,8 @@ export class UserProgressController {
}

@UseGuards(AuthGuard)
@Put(':courseId')
updateOne(@Request() req, @Param('courseId') courseId: number) {
return this.userProgressService.update(+req.user.userId, +courseId);
@Put()
updateOne(@Request() req, @Body() dto: UpdateUserProgressDto) {
return this.userProgressService.update(+req.user.userId, +dto.courseId);
}
}
10 changes: 10 additions & 0 deletions apps/client/api/tool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { http } from "./http";

interface DailySentenceVo {
zh: string
en: string
}

export async function fetchDailySentence() {
return await http.get<DailySentenceVo, DailySentenceVo>("/tool/dailySentence");
}
17 changes: 17 additions & 0 deletions apps/client/api/userProgress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { http } from "./http";

interface UserProgressVo {
courseId: number
}

interface UserProgressDto {
courseId: number
}

export async function fetchUserProgress() {
return await http.get<UserProgressVo, UserProgressVo>("/user-progress");
}

export async function fetchUpdateProgress(dto: UserProgressDto) {
return await http.put<UserProgressVo, UserProgressVo>("/user-progress", dto);
}
78 changes: 66 additions & 12 deletions apps/client/components/main/Summary.vue
Original file line number Diff line number Diff line change
@@ -1,31 +1,76 @@
<template>
<div>
<n-modal v-model:show="showModal" transform-origin="center">
<n-card style="width: 800px; height: 400px" title="结算面板" :bordered="false" size="huge" role="dialog"
aria-modal="true">
不错不错 又学到了那么多句子和单词 加油 坚持就是胜利:)
<template #footer>
<dialog className="modal" :open="showModal">
<div className="modal-box max-w-[48rem]">
<h3 className="font-bold text-lg mb-4">🎉 Congratulations!</h3>
<div class="flex flex-col">
<div class="flex">
<n-button @click="handleDoAgain">再来一次</n-button>
<n-button @click="handleGoToNextCourse">开始下一课</n-button>
<span class="text-6xl font-bold">"</span>
<div class="flex-1 text-xl text-center leading-loose">{{ enSentence }}</div>
<span class="text-6xl font-bold invisible">"</span>
</div>
</template>
</n-card>
</n-modal>

<div class="flex">
<span class="text-6xl font-bold invisible">"</span>
<div class="flex-1 text-center text-xl leading-loose">{{ zhSentence }}</div>
<span class="text-6xl font-bold">"</span>
</div>
</div>
<div className="modal-action">
<button class="btn" @click="handleDoAgain">再来一次</button>
<button class="btn" @click="handleGoToNextCourse">开始下一课</button>
</div>
</div>
<canvas ref="confettiCanvasRef" class="absolute top-0 left-0 h-full w-full pointer-events-none"></canvas>
</dialog>
</div>
</template>

<script setup lang="ts">
import { useCourseStore } from "~/store/course";
import { useSummary } from "~/composables/main/summary";
import { useDailySentence, useSummary } from "~/composables/main/summary";
import { useGameMode } from "~/composables/main/game";
import { fetchUpdateProgress } from "~/api/userProgress";
import confetti from 'canvas-confetti';
const useConfetti = () => {
const confettiCanvasRef = ref<HTMLCanvasElement>()
const playConfetti = () => {
console.log('----- 1');
const myConfetti = confetti.create(confettiCanvasRef.value, {
resize: true,
useWorker: true
})
myConfetti({
particleCount: 300,
spread: 180,
origin: { y: -0.1 },
startVelocity: -35
})
}
return {
confettiCanvasRef,
playConfetti,
}
}
const { confettiCanvasRef, playConfetti } = useConfetti()
const courseStore = useCourseStore();
const { showModal, hideSummary } = useSummary();
watch(showModal, (val) => {
val && setTimeout(() => {
playConfetti()
}, 300);
})
const { handleDoAgain } = useDoAgain()
const { handleGoToNextCourse } = useGoToNextCourse()
const { zhSentence, enSentence } = useDailySentence()
function useDoAgain() {
const { showQuestion } = useGameMode();
Expand All @@ -51,7 +96,16 @@ function useGoToNextCourse() {
+router.currentRoute.value.params.id
);
router.push(`/main/${courseStore.currentCourse?.id}`);
console.log(courseStore.currentCourse.id)
if (!courseStore.currentCourse.id) {
return
}
await fetchUpdateProgress({
courseId: courseStore.currentCourse.id
})
router.push(`/main/${courseStore.currentCourse.id}`);
hideSummary();
showQuestion();
}
Expand Down
28 changes: 28 additions & 0 deletions apps/client/composables/main/summary.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { fetchDailySentence } from "~/api/tool";

const showModal = ref(false);
export function useSummary() {
function showSummary() {
Expand All @@ -14,3 +16,29 @@ export function useSummary() {
hideSummary,
};
}

const enSentence = ref('To be, or not to be, that is the question.')
const zhSentence = ref('生存还是毁灭,这是一个问题。')
const setenceLoading = ref(false)
export function useDailySentence() {
const getDailySentence = async () => {
if (!setenceLoading.value) {
const {
en,
zh
} = await fetchDailySentence()
enSentence.value = en
zhSentence.value = zh
setenceLoading.value = true
}
}

onMounted(() => {
getDailySentence()
})

return {
enSentence,
zhSentence
}
}
Empty file.
2 changes: 2 additions & 0 deletions apps/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
"dependencies": {
"@nuxt/image": "^1.3.0",
"@pinia/nuxt": "^0.5.1",
"@types/canvas-confetti": "^1.6.4",
"axios": "^1.6.6",
"canvas-confetti": "^1.9.2",
"pinia": "^2.1.7"
}
}
75 changes: 62 additions & 13 deletions apps/client/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@
Star us on GitHub
</button>
</a>
<NuxtLink href="/main/1">
<button
class="btn btn-outline w-48 hover:text-fuchsia-400 hover:border-fuchsia-400 hover:bg-fuchsia-100 text-fuchsia-300 border-fuchsia-300"
>
Go and get it <kbd class="kbd"> ↵ </kbd>
</button>
</NuxtLink>
<button
:disabled="initing"
@click="handleKeydown"
class="btn btn-outline w-48 hover:text-fuchsia-400 hover:border-fuchsia-400 hover:bg-fuchsia-100 text-fuchsia-300 border-fuchsia-300">
<span v-show="initing" class="loading loading-spinner"></span>
Go and get it <kbd class="kbd"> ↵ </kbd>
</button>
</div>
<div
class="w-1/2 flex items-center justify-center group select-none cursor-pointer rounded-xl relative m-4"
Expand Down Expand Up @@ -77,27 +77,76 @@
</template>

<script setup lang="ts">
import { fetchUpdateProgress, fetchUserProgress } from "~/api/userProgress";
import { useUserStore } from "~/store/user";
import { registerShortcut, cancelShortcut } from "~/utils/keyboardShortcuts";
registerShortcutToStart();
const useProgress = () => {
const activeCourseId = ref(1)
const ACTIVE_COURSE_ID = 'activeCourseId'
const initing = ref(false)
const initProgress = async () => {
initing.value = true
const { courseId } = await fetchUserProgress()
activeCourseId.value = +courseId
updateProgressLocal(+courseId)
initing.value = false
}
const updateProgress = async (courseId: number) => {
const { courseId: updatedCourseId } = await fetchUpdateProgress({courseId})
updateProgressLocal(updatedCourseId)
}
const updateProgressLocal = async (courseId: number) => {
localStorage.setItem(ACTIVE_COURSE_ID, `${courseId}`)
}
return {
activeCourseId,
initing,
updateProgressLocal,
updateProgress,
initProgress
}
}
const { handleKeydown, initing } = useShortcutToGame();
function registerShortcutToStart() {
function useShortcutToGame() {
const router = useRouter();
const userStore = useUserStore();
const { activeCourseId, initing, initProgress } = useProgress()
function handleKeydown() {
router.push("/main/1");
if (userStore.user) {
if (initing.value)
return
router.push(`/main/${activeCourseId.value}`);
} else {
router.push("/main/1");
}
}
onMounted(() => {
registerShortcut("enter", handleKeydown);
console.log(userStore.user);
if (userStore.user) {
initProgress()
}
});
onUnmounted(() => {
cancelShortcut("enter", handleKeydown);
});
}
return {
initing,
handleKeydown
}
}
</script>

<style>
Expand Down
Loading

0 comments on commit baa7b95

Please sign in to comment.