Skip to content

Commit

Permalink
Merge pull request #74 from dnd-side-project/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
yoonncho authored Mar 3, 2023
2 parents 2f491b4 + 77d2eb8 commit 828fc9f
Show file tree
Hide file tree
Showing 51 changed files with 1,048 additions and 575 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"axios": "^1.3.2",
"clsx": "^1.2.1",
"dayjs": "^1.11.7",
"immer": "^9.0.19",
"lottie-web": "^5.10.2",
"next": "13.1.6",
"query-string": "^8.1.0",
Expand Down
Binary file added public/assets/images/android_screenshot_1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/android_screenshot_2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/nemoni.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions src/api/services/DayBlock.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export default interface DayBlockService {
Type.UpdateDailyReviewParams,
Type.UpdateDailyReviewResponse
>
deleteDailyReview: ServiceFunc<
Type.GetDailyReviewParams,
Record<string, never>
>

/** 태스크 */
createTaskInBlock: ServiceFunc<
Expand All @@ -64,4 +68,10 @@ export default interface DayBlockService {
Type.UpdateMyProfileResponse
>
getMyProfile: ServiceFunc<Type.GetMyProfileParams, Type.GetMyProfileResponse>

/** 유저 */
checkUniqueNickname: ServiceFunc<
Type.CheckUniqueNicknameParams,
Type.CheckUniqueNicknameResponse
>
}
46 changes: 42 additions & 4 deletions src/api/services/DayBlockAxiosAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export default class DayBlockAxiosAPI implements DayBlockService {
updateBlock(params: Type.UpdateBlockParams) {
return API.patch<Type.UpdateBlockResponse>(`/api/block/${params.blockId}`, {
title: params.title,
emoticon: params.emoticon,
blockColor: params.blockColor,
emoji: params.emoji,
backgroundColor: params.backgroundColor,
isSecret: params.isSecret,
})
}
Expand Down Expand Up @@ -66,6 +66,9 @@ export default class DayBlockAxiosAPI implements DayBlockService {
params,
)
}
deleteDailyReview({ reviewId }: Type.GetDailyReviewParams) {
return API.delete(`/api/review/${reviewId}`)
}

/** 태스크 */
createTaskInBlock(params: Type.CreateTaskInBlockParams) {
Expand All @@ -75,11 +78,14 @@ export default class DayBlockAxiosAPI implements DayBlockService {
)
}
updateTaskInBlock(params: Type.UpdateTaskInBlockParams) {
return API.put<Type.UpdateTaskInBlockResponse>(
return API.patch<Type.UpdateTaskInBlockResponse>(
`/api/task/${params.taskId}`,
params,
{ content: params.content },
)
}
updateTaskStatus(params: Type.UpdateTaskStatusParams) {
return API.patch(`/api/task/status/${params.taskId}`)
}
deleteTaskInBlock(params: Type.DeleteTaskInBlockParams) {
return API.delete<Type.DeleteTaskInBlockResponse>(
`/api/task/${params.taskId}`,
Expand All @@ -93,4 +99,36 @@ export default class DayBlockAxiosAPI implements DayBlockService {
getMyProfile() {
return API.get<Type.GetMyProfileResponse>(`/api/user`)
}

/** 유저 */
checkUniqueNickname({ nickname }: Type.CheckUniqueNicknameParams) {
return API.get<Type.CheckUniqueNicknameResponse>(
`/api/user/nickname/${nickname}`,
)
}

/** 기타 */
async getMyDailyBlockMetric({
date,
}: Type.GetMyDailyBlockMetricParams): Promise<Type.GetMyDailyBlockMetricResponse> {
const myProfile = await this.getMyProfile().then(({ data }) => data)
const blocks = await this.getDayBlocks({ date }).then(({ data }) => data)

const numOfTasks = blocks.numOfTotalTasks
const numOfdoneTasks =
blocks.blocks.reduce(
(res, { numOfDoneTask }) => res + (numOfDoneTask || 0),
0,
) || 0

return {
date,
user: myProfile,
numOfBlocks: blocks.numOfTotalBlocks,
numOfTasks,
numOfdoneTasks,
percentageOfDoneTasks:
numOfTasks === 0 ? 0 : Math.round((numOfdoneTasks / numOfTasks) * 100),
}
}
}
49 changes: 31 additions & 18 deletions src/api/types/base.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,16 @@ import { UserProfile } from '@/types/common.type'
export type GetDailyBlocksOnWeekParams = {
date: string
}
export type GetDailyBlocksOnWeekResponse = {
user: string
dailyBlocks: Array<DailyBlock>
}
export type GetDailyBlocksOnWeekResponse = Array<DailyBlock>

export type GetDayBlocksParams = {
date: string
}
export type GetDayBlocksResponse = {
date: string
totalBlock: number
totalTask: number
reviewId?: number
numOfTotalBlocks: number
numOfTotalTasks: number
reviewId?: number | null
blocks: Array<BlockDetail>
}

Expand All @@ -27,12 +24,12 @@ export type GetSingleBlockParams = {
export type GetSingleBlockResponse = {
date: string
title: string
emoticon: string
blockColor: string
emoji: string
backgroundColor: string
isSecret: boolean
}

export type GetSavedBlocksResponse = Omit<BlockDetail, 'sumOfDoneTask'>[]
export type GetSavedBlocksResponse = Omit<BlockDetail, 'numOfDoneTask'>[]

export type SaveBlockParams = {
blockId: number
Expand All @@ -41,8 +38,8 @@ export type SaveBlockParams = {
export type CreateBlockParams = {
date: string
title: string
emoticon: string
blockColor: string
emoji: string
backgroundColor: string
isSecret: boolean
}
export type CreateBlockResponse = {
Expand All @@ -51,7 +48,7 @@ export type CreateBlockResponse = {

export type CreateDailyReviewParams = {
date: string
emoticon: string
emoji: string
review: string
isSecret: boolean
}
Expand Down Expand Up @@ -92,18 +89,20 @@ export type DeleteTaskInBlockResponse = unknown
export type UpdateBlockParams = {
blockId: number
title: string
emoticon: string
blockColor: string
emoji: string
backgroundColor: string
isSecret: boolean
}

export type UpdateBlockResponse = {
title: string
emoticon: string
blockColor: string
emoji: string
backgroundColor: string
isSecret: boolean
}

export type UpdateTaskStatusParams = { taskId: number }

export type UpdateMyProfileParams = UserProfile
export type UpdateMyProfileResponse = UserProfile

Expand All @@ -113,5 +112,19 @@ export type GetMyProfileResponse = UserProfile
export type DeleteSavedBlockParams = { blockId: number }
export type DeleteSavedBlockResponse = Record<string, never>

export type LoadSavedBlockParams = { date: string; blockId: number[] }
export type LoadSavedBlockParams = { date: string; blockIds: number[] }
export type LoadSavedBlockResponse = Record<string, never>

/** 기타 */
export type GetMyDailyBlockMetricParams = { date: string }
export type GetMyDailyBlockMetricResponse = {
date: string
user: UserProfile
numOfBlocks: number
numOfTasks: number
numOfdoneTasks: number
percentageOfDoneTasks: number
}

export type CheckUniqueNicknameParams = { nickname: string }
export type CheckUniqueNicknameResponse = { isDuplicated: boolean }
22 changes: 17 additions & 5 deletions src/components/Block/AddTaskButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
import { dayBlockAPI } from '@/api'
import { CreateTaskInBlockParams } from '@/api/types/base.types'
import Button from '@/components/Button'
import { AddIcon } from '@/components/Icons'
import useHttpRequest from '@/hooks/useHttpRequest'
import useBlockListStore from '@/store/blocks'

const AddTaskButton = ({ blockId }: { blockId: number }) => {
const addNewTaskStore = useBlockListStore((state) => state.addNewTask)
const [, createTask] = useHttpRequest((params: CreateTaskInBlockParams) =>
dayBlockAPI.createTaskInBlock(params).then(({ data }) => data),
)

const handleClick = () => {
dayBlockAPI.createTaskInBlock({
blockId,
content: '',
})
createTask(
{ blockId, content: '' },
{
onSuccess: ({ taskId: newTaskId }) => {
addNewTaskStore(blockId, newTaskId)
},
},
)
}

return (
<Button
color="white"
backgroundColor="white"
rounded="sm"
className="!px-3 !py-1 !w-fit"
onClick={handleClick}
Expand Down
59 changes: 53 additions & 6 deletions src/components/Block/Task/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,73 @@ import TaskCheckBox, { OnChange } from '@/components/TaskCheckBox'
import type { Task as TaskType } from '@/types/block'
import useDebounce from '@/hooks/useDebounce'
import { dayBlockAPI } from '@/api'
import useHttpRequest from '@/hooks/useHttpRequest'
import {
DeleteTaskInBlockParams,
UpdateTaskInBlockParams,
UpdateTaskStatusParams,
} from '@/api/types/base.types'
import useBlockListStore from '@/store/blocks'

const Task = ({ isDone, task, taskId }: TaskType) => {
const Task = ({
isDone,
task,
taskId,
blockId,
}: TaskType & { blockId: number }) => {
const [isChecked, setIsChecked] = useState(isDone)
const [taskValue, setTaskValue] = useState<string>('')
const [taskValue, setTaskValue] = useState<string>(task)
const debouncedValue = useDebounce<string>(taskValue, 500)
const deleteTaskStore = useBlockListStore((state) => state.deleteTask)
const updateTaskStore = useBlockListStore((state) => state.updateTask)
const updateTaskStatusStore = useBlockListStore(
(state) => state.updateTaskStatus,
)

const [, updateTask] = useHttpRequest((params: UpdateTaskInBlockParams) =>
dayBlockAPI.updateTaskInBlock(params).then(({ data }) => data),
)
const [, updateTaskStatus] = useHttpRequest(
(params: UpdateTaskStatusParams) =>
dayBlockAPI.updateTaskStatus(params).then(({ data }) => data),
)
const [, deleteTask] = useHttpRequest((params: DeleteTaskInBlockParams) =>
dayBlockAPI.deleteTaskInBlock(params).then(({ data }) => data),
)

const handleCheckTask: OnChange = ({ selected }) => {
setIsChecked(selected)
updateTaskStatus(
{ taskId },
{ onSuccess: () => updateTaskStatusStore(blockId, taskId, selected) },
)
}

const handleTaskChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
setTaskValue(e.target.value)
}

const handleDelete = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (taskValue.length === 0 && e.key.toLowerCase() === 'backspace') {
deleteTask(
{ taskId },
{
onSuccess: () => deleteTaskStore(blockId, taskId),
},
)
}
}

useEffect(() => {
debouncedValue &&
dayBlockAPI.updateTaskInBlock({
if (!debouncedValue) return
updateTask(
{
taskId,
content: debouncedValue,
})
}, [taskId, debouncedValue])
},
{ onSuccess: () => updateTaskStore(blockId, taskId, debouncedValue) },
)
}, [debouncedValue])

return (
<div className="flex mb-3">
Expand All @@ -51,6 +97,7 @@ const Task = ({ isDone, task, taskId }: TaskType) => {
},
)}
disabled={!!isChecked}
onKeyDown={handleDelete}
/>
</div>
)
Expand Down
20 changes: 10 additions & 10 deletions src/components/Block/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ const Template: ComponentStory<typeof Block> = (args) => <Block {...args} />

const MOCK_DATA: BlockDetail = {
blockId: 1,
color: '#FF7154',
icon: '😂',
backgroundColor: '#FF7154',
emoji: '😂',
title: '출근 준비',
sumOfTask: 4,
sumOfDoneTask: 2,
numOfTasks: 4,
numOfDoneTask: 2,
tasks: [
{
taskId: 0,
Expand All @@ -40,15 +40,15 @@ const MOCK_DATA: BlockDetail = {
],
}

const { color, icon, title, sumOfTask, sumOfDoneTask, tasks } = MOCK_DATA
const { backgroundColor, emoji, title, numOfTasks, numOfDoneTask, tasks } =
MOCK_DATA

export const Basic = Template.bind({})
Basic.args = {
color,
icon,
backgroundColor,
emoji,
title,
sumOfTask,
sumOfDoneTask,
numOfTasks,
numOfDoneTask,
tasks,
locked: false,
}
Loading

0 comments on commit 828fc9f

Please sign in to comment.