Skip to content

Commit

Permalink
feat: 카드 뭉치 삭제/초기화/이름을 변경할 수 있다.
Browse files Browse the repository at this point in the history
deploy merge
  • Loading branch information
padosum committed Mar 1, 2023
2 parents 12aba54 + 62c52de commit 15ed894
Show file tree
Hide file tree
Showing 17 changed files with 546 additions and 74 deletions.
79 changes: 76 additions & 3 deletions src/App.vue
Expand Up @@ -8,6 +8,37 @@
<v-toolbar-title>
<div data-testid="toolbar-title">{{ pageTitle }}</div>
</v-toolbar-title>

<v-spacer></v-spacer>

<teamplte v-if="route.name === 'LearnsetView'">
<BaseButton
text=""
icon
data-testid="edit"
variant="default"
@click="toggleModal"
>
<v-icon>mdi-pencil</v-icon>
</BaseButton>

<BaseButton
text=""
icon
data-testid="delete"
variant="default"
@click="deleteLearnset"
>
<v-icon>mdi-delete</v-icon>
</BaseButton>
<EditLearnsetModal
:learnset-title="pageTitle"
title="카드 뭉치 이름 수정하기"
ref="modal"
@edit-learnset="editLearnset"
@reset-learnset="resetLearnset"
/>
</teamplte>
</v-app-bar>
<v-main>
<router-view />
Expand All @@ -17,23 +48,65 @@

<script setup lang="ts">
import NavigationDrawer from '@/components/NavigationDrawer.vue';
import BaseButton from '@/components/BaseButton.vue';
import EditLearnsetModal from '@/components/EditLearnsetModal.vue';
import { ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useRoute, useRouter } from 'vue-router';
import { useStore } from 'vuex';
import type { MyStore } from '@/store/types';
import { MutationTypes } from '@/store/mutations';
const drawer = ref(true);
const route = useRoute();
const router = useRouter();
const store: MyStore = useStore();
const pageTitle = computed(() => {
const learnset = computed(() => {
const learnset = store.state.learnsets.find(
({ id }) => id === route.params.id
);
return learnset ? learnset.name : 'Dashboard';
return learnset;
});
const pageTitle = computed(() => {
return learnset.value ? learnset.value.name : 'Dashboard';
});
const deleteLearnset = () => {
const deleteLearnset = confirm(
`"${pageTitle.value}" 카드 뭉치를 삭제하시겠습니까?`
);
if (deleteLearnset) {
router.push('/');
store.commit(MutationTypes.DELETE_LEARNSET, learnset.value);
}
return;
};
const modal = ref<InstanceType<typeof EditLearnsetModal> | null>(null);
const toggleModal = () => {
modal.value?.toggleModal();
};
const editLearnset = (newTitle: string) => {
if (learnset.value) {
learnset.value.name = newTitle;
store.commit(MutationTypes.UPDATE_LEARNSET, learnset.value);
}
};
const resetLearnset = () => {
if (learnset.value) {
store.commit(MutationTypes.RESET_LEARNSET, learnset.value.id);
}
};
</script>

<style scoped></style>
24 changes: 9 additions & 15 deletions src/components/AddLearnsetModal.vue
@@ -1,11 +1,6 @@
<template>
<BaseButton
text="open"
class="d-none"
role="button"
@click="openModal = true"
/>
<v-dialog v-model="openModal" persistent v-if="openModal" :class="modalSize">
<BaseButton text="open" class="d-none" role="button" @click="open = true" />
<v-dialog v-model="open" v-if="open" :class="modalSize">
<v-card>
<v-card-title>
<span class="text-h5">{{ title }}</span>
Expand All @@ -23,10 +18,10 @@
<v-spacer></v-spacer>
<BaseButton
text="취소"
color="primary"
color="primary-darken-2"
variant="text"
data-testid="close"
@click="openModal = false"
@click="open = false"
/>
<BaseButton
text="추가"
Expand All @@ -46,7 +41,11 @@ import BaseButton from './BaseButton.vue';
import { ref, computed, watchEffect } from 'vue';
import { useDisplay } from 'vuetify';
import useModal from '@/hooks/useModal';
const { open, toggleModal } = useModal();
const emit = defineEmits(['addLearnset']);
const props = defineProps({
title: {
type: String,
Expand All @@ -57,16 +56,11 @@ const props = defineProps({
},
});
const openModal = ref(false);
const learnsetTitle = ref('');
watchEffect(() => (learnsetTitle.value = props.learnsetTitle));
const toggleModal = () => {
openModal.value = !openModal.value;
};
const addLearnset = () => {
openModal.value = false;
open.value = false;
emit('addLearnset', learnsetTitle.value);
};
Expand Down
102 changes: 102 additions & 0 deletions src/components/EditLearnsetModal.vue
@@ -0,0 +1,102 @@
<template>
<BaseButton text="open" class="d-none" role="button" @click="open = true" />
<v-dialog v-model="open" v-if="open" :class="modalSize">
<v-card>
<v-card-title>
<span class="text-h5">{{ title }}</span>
</v-card-title>
<v-card-text>
<v-container>
<v-text-field
label="카드 뭉치 이름"
required
v-model="learnsetTitle"
></v-text-field>
</v-container>
</v-card-text>
<v-card-actions>
<BaseButton
text="진행 상태 초기화"
color="error"
variant="text"
data-testid="close"
@click="resetLearnset"
/>
<v-spacer></v-spacer>
<BaseButton
text="취소"
color="primary-darken-2"
variant="text"
data-testid="close"
@click="open = false"
/>
<BaseButton
text="수정"
color="primary"
variant="text"
data-testid="save"
@click="editLearnset"
/>
</v-card-actions>
</v-card>
</v-dialog>
</template>

<script setup lang="ts">
import BaseButton from './BaseButton.vue';
import { ref, computed, watchEffect } from 'vue';
import { useDisplay } from 'vuetify';
import useModal from '@/hooks/useModal';
const { open, toggleModal } = useModal();
const emit = defineEmits(['editLearnset', 'resetLearnset']);
const props = defineProps({
title: {
type: String,
},
learnsetTitle: {
type: String,
required: true,
},
});
const learnsetTitle = ref('');
watchEffect(() => (learnsetTitle.value = props.learnsetTitle));
const resetLearnset = () => {
const reset = confirm('이 카드 뭉치의 학습 진행 상태를 초기화하시겠습니까?');
if (reset) {
open.value = false;
emit('resetLearnset');
}
return;
};
const editLearnset = () => {
open.value = false;
emit('editLearnset', learnsetTitle.value);
};
const { name } = useDisplay();
const modalSize = computed(() => {
switch (name.value) {
case 'xs':
case 'sm':
return 'w-100';
case 'md':
return 'w-75';
default:
return 'w-25';
}
});
defineExpose({
toggleModal,
});
</script>

<style scoped></style>
25 changes: 25 additions & 0 deletions src/components/__tests__/EditLearnsetModal.spec.ts
@@ -0,0 +1,25 @@
import EditLearnsetModal from '@/components/EditLearnsetModal.vue';
import { render, fireEvent } from '@testing-library/vue';
import vuetify from '@/utils/setupVuetify';

describe('EditLearnsetModal Component', () => {
const title = '카드 뭉치 추가하기';
const learnsetTitle = 'learnset title';

it(`Modal이 전달한 text와 함께 렌더링된다.`, async () => {
const { getByRole } = render(EditLearnsetModal, {
global: {
plugins: [vuetify],
},
props: {
title,
learnsetTitle,
},
});

// open
await fireEvent.click(getByRole('button'));
const input = getByRole('textbox', { name: '카드 뭉치 이름' });
expect(input).toHaveValue(learnsetTitle);
});
});
70 changes: 34 additions & 36 deletions src/components/__tests__/LearnsetCard.spec.ts
Expand Up @@ -31,6 +31,8 @@ describe('LearnsetCard Component', () => {
repetition: 0,
interval: 0,
reviewDate: '',
correctCnt: 0,
incorrectCnt: 0,
};

it('카드의 질문이 렌더링 된다.', () => {
Expand All @@ -47,24 +49,23 @@ describe('LearnsetCard Component', () => {
});

it('정답 확인 버튼을 클릭하면 카드의 정답과 점수를 매길 수 있는 버튼이 렌더링 된다.', async () => {
const { getByText, getAllByRole, getByRole, getByTestId } = render(
LearnsetCard,
{
global: {
plugins: [router, vuetify, markdownItPlugin],
},
props: {
card: CARD_DATA,
review: true,
},
data() {
return {
showBack: false,
submitted: false,
};
},
}
);

const { getByText, getAllByRole, getByTestId } = render(LearnsetCard, {
global: {
plugins: [router, vuetify, markdownItPlugin],
},
props: {
card: CARD_DATA,
review: true,
},
data() {
return {
showBack: false,
submitted: false,
};
},
});

await fireEvent.click(getByTestId('show-answer-btn'));

expect(getByText('반갑습니다')).toBeInTheDocument();
Expand All @@ -80,24 +81,21 @@ describe('LearnsetCard Component', () => {
});

it('점수를 매길 수 있는 버튼을 클릭하면 더 이상 버튼을 클릭할 수 없다.', async () => {
const { queryByRole, getAllByRole, getByRole, getByTestId } = render(
LearnsetCard,
{
global: {
plugins: [router, vuetify, markdownItPlugin],
},
props: {
card: CARD_DATA,
review: true,
},
data() {
return {
showBack: false,
submitted: false,
};
},
}
);
const { getAllByRole, getByRole, getByTestId } = render(LearnsetCard, {
global: {
plugins: [router, vuetify, markdownItPlugin],
},
props: {
card: CARD_DATA,
review: true,
},
data() {
return {
showBack: false,
submitted: false,
};
},
});

await fireEvent.click(getByTestId('show-answer-btn'));

Expand Down
12 changes: 12 additions & 0 deletions src/hooks/useModal.ts
@@ -0,0 +1,12 @@
import { ref } from 'vue';
export default function useModal() {
const open = ref(false);
const toggleModal = () => {
open.value = !open.value;
};

return {
open,
toggleModal,
};
}

1 comment on commit 15ed894

@vercel
Copy link

@vercel vercel bot commented on 15ed894 Mar 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

flashmd – ./

flashmd-git-main-padosum.vercel.app
flashmd-padosum.vercel.app
flash.padosum.dev
flashmd.vercel.app

Please sign in to comment.