Skip to content

Commit

Permalink
Merge pull request #26 from raipen/feat/wordlist-delete-and-rename
Browse files Browse the repository at this point in the history
Feat: wordlist delete and rename
  • Loading branch information
raipen authored Apr 1, 2024
2 parents e7f0260 + cac330c commit 6754981
Show file tree
Hide file tree
Showing 24 changed files with 444 additions and 174 deletions.
39 changes: 39 additions & 0 deletions src/DTO/wordbook.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,46 @@ export const showWordbookSchema = {
},
} as const;

export const deleteWordbookSchema = {
tags: ['Wordbook'],
summary: '단어장 삭제',
headers: AuthorizationHeader,
body: {
type: 'object',
required: ['bookId'],
properties: {
bookId: { type: 'string' },
},
},
response: {
200: returnType,
...errorSchema(
)
},
} as const;

export const renameWordbookSchema = {
tags: ['Wordbook'],
summary: '단어장 이름 변경',
headers: AuthorizationHeader,
body: {
type: 'object',
required: ['bookId', 'title'],
properties: {
bookId: { type: 'string' },
title: { type: 'string' },
},
},
response: {
200: returnType,
...errorSchema(
)
},
} as const;

export type getWordbookListInterface = SchemaToInterface<typeof getWordbookListSchema> & { Body: { userId: string } };
export type createWordbookInterface = SchemaToInterface<typeof createWordbookSchema> & { Body: { userId: string } };
export type hideWordbookInterface = SchemaToInterface<typeof hideWordbookSchema> & { Body: { userId: string } };
export type showWordbookInterface = SchemaToInterface<typeof showWordbookSchema> & { Body: { userId: string } };
export type deleteWordbookInterface = SchemaToInterface<typeof deleteWordbookSchema> & { Body: { userId: string } };
export type renameWordbookInterface = SchemaToInterface<typeof renameWordbookSchema> & { Body: { userId: string } };
24 changes: 24 additions & 0 deletions src/back/api/routes/wordbook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,30 @@ const api: FastifyPluginAsync = async (server: FastifyInstance) => {
reply.status(200).send(result);
}
);

server.delete<WordbookDTO.deleteWordbookInterface>(
'/',
{
schema: WordbookDTO.deleteWordbookSchema,
preValidation: checkUser
},
async (request, reply) => {
const result = await WordbookService.deleteWordbook(request.body);
reply.status(200).send(result);
}
);

server.patch<WordbookDTO.renameWordbookInterface>(
'/name',
{
schema: WordbookDTO.renameWordbookSchema,
preValidation: checkUser
},
async (request, reply) => {
const result = await WordbookService.renameWordbook(request.body);
reply.status(200).send(result);
}
);
};

export default api;
8 changes: 5 additions & 3 deletions src/back/loaders/errorHandler.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FastifyRequest, FastifyReply, FastifyError } from 'fastify';
import { ErrorWithToast, ValidationError } from '@errors';
import { ErrorWithToast, ValidationError,NotFoundError } from '@errors';
import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library';
import ErrorConfig from '@errors/config';

Expand Down Expand Up @@ -34,8 +34,10 @@ export default (
}
if(error instanceof PrismaClientKnownRequestError) {
if(error.code === 'P2025') {
//error.toast = '찾을 수 없는 데이터가 포함되어 있습니다.';
return reply.code(404).send(error);
return reply.code(404).send({
error: NotFoundError.name,
message: '요청하신 데이터를 찾을 수 없습니다.',
});
}
//error.toast = '잘못된 데이터가 입력되었습니다.';
return reply.code(400).send(error);
Expand Down
27 changes: 26 additions & 1 deletion src/back/repository/wordbook.repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export const getWordbook = async (wordbookId: string, userId: string) => await p
const getWordbookList = (isHidden:boolean) => async (userId: string) => await prisma.wordbook.findMany({
where: {
userId,
isHidden
isHidden,
deletedAt: null
},
include: {
_count: {
Expand Down Expand Up @@ -51,3 +52,27 @@ const changeWordbookHidden = (isHidden:boolean) => async (userId: string, wordbo

export const hideWordbook = changeWordbookHidden(true);
export const showWordbook = changeWordbookHidden(false);

export const deleteWordbook = async (userId: string, wordbookId: string) => {
await prisma.wordbook.update({
where: {
uuid: wordbookId,
userId
},
data: {
deletedAt: new Date()
}
});
}

export const renameWordbook = async (userId: string, wordbookId: string, title: string) => {
await prisma.wordbook.update({
where: {
uuid: wordbookId,
userId
},
data: {
title
}
});
}
12 changes: 12 additions & 0 deletions src/back/services/wordbook.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,15 @@ export async function showWordbook({userId, bookId}: WordbookDTO.showWordbookInt
await WordbookRepo.showWordbook(userId, bookId);
return getWrodbookList({userId});
}

export async function deleteWordbook({userId, bookId}: WordbookDTO.deleteWordbookInterface['Body'])
: Promise<WordbookDTO.deleteWordbookInterface['Reply']['200']> {
await WordbookRepo.deleteWordbook(userId, bookId);
return getWrodbookList({userId});
}

export async function renameWordbook({userId, bookId, title}: WordbookDTO.renameWordbookInterface['Body'])
: Promise<WordbookDTO.renameWordbookInterface['Reply']['200']> {
await WordbookRepo.renameWordbook(userId, bookId, title);
return getWrodbookList({userId});
}
41 changes: 0 additions & 41 deletions src/front/components/WordbookElement.tsx

This file was deleted.

13 changes: 12 additions & 1 deletion src/front/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ export const WordbookContainer = styled.div`
margin-bottom: 10px;
border-top: 1px solid var(--main-color);
padding: 10px;
gap: 10px;
`;

export const AddWordbookContainer = styled(WordbookContainer)`
Expand All @@ -228,7 +229,10 @@ export const AddWordbookContainer = styled(WordbookContainer)`

export const WordbookMenu = styled.div`
${FlexColumnCenter};
${clickable};
&>span{
${clickable};
font-size: 1.2rem;
}
color: var(--muted-text-color);
font-weight: 300;
gap: 10px;
Expand All @@ -238,12 +242,18 @@ export const WordbookInfo = styled.div`
${FlexColumnLeftStart};
font-size: 1rem;
font-weight: 300;
max-width: calc(100% - 50px);
flex: 1;
color: var(--muted-text-color);
`;

export const WordbookName = styled.div`
font-size: 1.5rem;
font-weight: 600;
max-width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
&>a:last-child {
color: var(--main-color);
&:hover {
Expand All @@ -253,6 +263,7 @@ export const WordbookName = styled.div`
}
&>input{
font-weight: 600;
width: calc(100% - 21px);
}
&>.material-icons-sharp{
font-size: 1rem;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { VocaMode } from "@utils/vocaModeEnum";
import useEditVocaList from "@hooks/useEditVocaList";
import {
VocaListElement,
Expand All @@ -14,7 +13,7 @@ import {
ReverseButtonContainingIcon,
ActivatableIcon,
ButtonWithHoverAnimation
} from './index';
} from '../index';
import useFetchUpdate from '@hooks/useFetchUpdate';
import { deleteVoca } from '@utils/apis/voca';

Expand All @@ -34,25 +33,25 @@ function WordInputWithMenu({word, onChange, disabled, moveWordUp, moveWordDown,
<div style={{display: 'flex', padding: '10px', alignItems: 'center'}}>
<ActivatableIcon onClick={moveWordUp} className="material-icons-sharp" tabIndex={-1} disabled={disable}>arrow_upward</ActivatableIcon>
<ActivatableIcon onClick={moveWordDown} className="material-icons-sharp" tabIndex={-1} disabled={disable}>arrow_downward</ActivatableIcon>
<MiniInput value={loadingDeleteVoca ? "삭제중" : word} onChange={onChange} disabled={disable}/>
<MiniInput value={loadingDeleteVoca ? "삭제중" : word} onChange={onChange} disabled={disable} placeholder="ex) apple"/>
<WarningClickableIcon disabled={disable} onClick={deleteWord(fetchDeleteVoca)} className="material-icons-sharp" tabIndex={-1} style={{fontSize:"1.5rem"}}>delete_forever</WarningClickableIcon>
</div>
);
}

function EditVocaList({setVocaMode}: {setVocaMode: React.Dispatch<React.SetStateAction<VocaMode>>}) {
function EditVocaList() {
const { vocaList, loadingSaveVocaList,
onChangeWord, onChangeMeans, reset, save,
deleteNewVoca, deleteMean,
deleteWord, deleteMean,
moveWordUp, moveWordDown } = useEditVocaList();

return (
<VocaListContainer style={{marginLeft: 0}}>
<Title>
<span>단어 편집</span>
<div style={{display: 'flex', gap: '10px'}}>
<ReverseButtonContainingIcon onClick={()=>reset(()=>setVocaMode(VocaMode.VIEW))}>취소</ReverseButtonContainingIcon>
<ButtonContainingIcon onClick={()=>save(()=>setVocaMode(VocaMode.VIEW))}>저장</ButtonContainingIcon>
<ReverseButtonContainingIcon onClick={reset}>취소</ReverseButtonContainingIcon>
<ButtonContainingIcon onClick={save}>저장</ButtonContainingIcon>
</div>
</Title>
<VocaListElement>
Expand All @@ -64,19 +63,19 @@ function EditVocaList({setVocaMode}: {setVocaMode: React.Dispatch<React.SetState
</div>
{vocaList.flatMap((voca,i) => [
<WordInputWithMenu key={3*i} word={voca.word} onChange={onChangeWord(i)} disabled={loadingSaveVocaList} moveWordUp={moveWordUp(i)} moveWordDown={moveWordDown(i)} deleteWord={deleteNewVoca(i,voca.id)}/>,
<WordInputWithMenu key={3*i} word={voca.word} onChange={onChangeWord(i)} disabled={loadingSaveVocaList} moveWordUp={moveWordUp(i)} moveWordDown={moveWordDown(i)} deleteWord={deleteWord(i,voca.id)}/>,
<SeparateLine key={3*i+1}/>,
<Meaning key={3*i+2}>
{voca.meaning.map((m,j) =>(
<MeaningCount key={j}>
<MiniInput value={m} onChange={onChangeMeans(i,j)} disabled={loadingSaveVocaList}/>
<MiniInput value={m} onChange={onChangeMeans(i,j)} disabled={loadingSaveVocaList} placeholder={j===0?"ex) 사과":"ex) 뜻"+(j+1)}/>
<UnactivatableIcon onClick={deleteMean(i,j)} className="material-icons-sharp" tabIndex={-1}>remove_circle_outline</UnactivatableIcon>
</MeaningCount>
))}
</Meaning>
])}
</VocaListElement>
<ButtonWithHoverAnimation onClick={()=>save(()=>setVocaMode(VocaMode.VIEW))}>저장</ButtonWithHoverAnimation>
<ButtonWithHoverAnimation onClick={save}>저장</ButtonWithHoverAnimation>
</VocaListContainer>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { VocaMode } from "@utils/vocaModeEnum";
import VocaListContext from '@context/VocaListContext';
import useFetchUpdate from '@hooks/useFetchUpdate';
import { useContext,useState } from 'react';
import {
VocaListElement,
Expand All @@ -13,7 +11,7 @@ import {
MeaningWithAnswer,
ButtonWithHoverAnimation,
ReverseButtonWithHoverAnimation
} from './index';
} from '../index';

const marking = (input: string[][], answer: {id:number,meaning: string[]}[]) => {
const commaSeparatedAnswer = answer.map(a => ({...a,meaning:a.meaning.map(b=>b.split(',').map(c=>c.trim()))}));
Expand All @@ -31,8 +29,8 @@ const marking = (input: string[][], answer: {id:number,meaning: string[]}[]) =>
return {detailMarking: detailMarking.map(({result}) => result), markingResult};
}

function TestVocaList({setVocaMode}: {setVocaMode: React.Dispatch<React.SetStateAction<VocaMode>>}) {
const { vocaList } = useContext(VocaListContext);
function TestVocaList() {
const { vocaList, viewMode } = useContext(VocaListContext);
const emptyVocaList = vocaList.map(voca => new Array(voca.meaning.length).fill(""));
const [inputList, setInputList] = useState(emptyVocaList);
const [result, setResult] = useState<{meaning: string[],correct: boolean}[][]|null>(null);
Expand Down Expand Up @@ -80,7 +78,7 @@ function TestVocaList({setVocaMode}: {setVocaMode: React.Dispatch<React.SetState
{result.filter(voca => voca.every(m => m.correct)).length}/{vocaList.length}
</div>}
{result!==null&&
<ReverseButtonWithHoverAnimation onClick={()=>setVocaMode(VocaMode.VIEW)}>
<ReverseButtonWithHoverAnimation onClick={viewMode}>
돌아가기
</ReverseButtonWithHoverAnimation>}
</VocaListContainer>
Expand Down
Loading

0 comments on commit 6754981

Please sign in to comment.