Skip to content

Commit

Permalink
enhance: add status filter as create calendar view (#147)
Browse files Browse the repository at this point in the history
  • Loading branch information
hudy9x authored Mar 24, 2024
1 parent c5f6afe commit 5f91543
Show file tree
Hide file tree
Showing 21 changed files with 223 additions and 128 deletions.
4 changes: 3 additions & 1 deletion packages/be-gateway/src/routes/project/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export default class ProjectViewController extends BaseController {
priority: string
point: string
groupBy: string
statusIds: string[]
}
}

Expand All @@ -49,7 +50,8 @@ export default class ProjectViewController extends BaseController {
date: data.date,
priority: data.priority,
point: data.point,
groupBy: data.groupBy
groupBy: data.groupBy,
statusIds: data.statusIds
} : {},

type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ export default function ListItem({
if (multiple && onMultiChange) {
onMultiChange(prev => {
// clear others selected, but itself
// when set `true` and in multiple mode, it will clear all value but itself
// Ex: user select an ALL item, then the others should be cleared
if (keepMeOnly) {
return [value]
}
Expand All @@ -50,7 +52,7 @@ export default function ListItem({
}

// click on a unselected item, select it
return [...prev.filter(p => p.id !== 'ALL'), value]
return [...prev.filter(p => p.id !== 'ALL'), value].reverse()
} else {
return prev
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,40 +28,49 @@ export default function CalMonthTask({
taskStatusId
}: ICalMonthTaskProps) {
const { filter } = useTaskFilter()
const { status: filterStatus } = filter
const { status: filterStatus, statusIds: filterStatusIds } = filter
const { color, type } = useStatusData(taskStatusId || '')
const { calendarView } = useCalendarContext()

if (filterStatus !== 'ALL' && filterStatus !== type) {
return null
const view = () => <Link href={link}>
<Draggable draggableId={id} index={index}>
{provided => (
<div
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
className="calendar-task-item relative">
{calendarView === ICalendarView.WEEK ? (
<CalTaskInWeek
color={color}
title={title}
assigneeId={assigneeId}
/>
) : (
<CalTaskInMonth
time={time}
color={color}
title={title}
assigneeId={assigneeId}
/>
)}
</div>
)}
</Draggable>
</Link>

// if statusIds contain ALL or nothing
// display view
if (filterStatusIds.includes('ALL') || !filterStatusIds.length) {
return view()
}


// if statusIds have some
// display tasks that have the same status id
if (filterStatusIds.includes(taskStatusId)) {
return view()
}

return (
<Link href={link}>
<Draggable draggableId={id} index={index}>
{provided => (
<div
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
className="calendar-task-item relative">
{calendarView === ICalendarView.WEEK ? (
<CalTaskInWeek
color={color}
title={title}
assigneeId={assigneeId}
/>
) : (
<CalTaskInMonth
time={time}
color={color}
title={title}
assigneeId={assigneeId}
/>
)}
</div>
)}
</Draggable>
</Link>
)
return null
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ export default function CalMonthTaskList({ day }: { day: Date }) {

const h = dueDate.getHours()
const m = dueDate.getMinutes()
const time = `${h > 9 ? (h > 12 ? h - 12 : h) : '0' + h}:${
m > 9 ? m : '0' + m
} ${h >= 12 ? 'PM' : 'AM'}`
const time = `${h > 9 ? (h > 12 ? h - 12 : h) : '0' + h}:${m > 9 ? m : '0' + m
} ${h >= 12 ? 'PM' : 'AM'}`

return (
<CalMonthTask
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.calendar-wrapper {
@apply flex flex-col justify-between divide-y dark:divide-gray-700 relative;
height: calc(100vh - 153px);
/* height: calc(100vh - 153px); */
height: 800px
}

.week-view.calendar-wrapper {
Expand Down
63 changes: 44 additions & 19 deletions packages/ui-app/app/_components/StatusSelectMultiple.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
import { Form, ListItemValue } from '@shared/ui'
import { useEffect, useState } from 'react'
import { useEffect, useMemo, useState } from 'react'
import { useProjectStatusStore } from '../../store/status'

const List = Form.List

interface IStatusSelectProps {
value?: string[]
noName?: boolean
className?: string
onChange?: (v: string[]) => void
title?: string
placeholder?: string
}

const defaultOption: ListItemValue = {
id: '0',
title: 'None'
maxDisplay?: number
}

export default function StatusSelectMultiple({
title,
className,
noName = false,
value,
onChange,
placeholder
placeholder,
maxDisplay = 3
}: IStatusSelectProps) {
// const selectOption = options.find(opt => opt.id === value);
const { statuses } = useProjectStatusStore()
Expand All @@ -38,16 +37,33 @@ export default function StatusSelectMultiple({
// update options list
useEffect(() => {
const statusList = statuses.map(stt => ({ id: stt.id, title: stt.name }))
statusList.push({
id: 'ALL',
title: 'All statuses'
})
setOptions(statusList as ListItemValue[])
}, [statuses])

// fill selectetd value after statues list updated
useEffect(() => {
if (options.length) {
const selectedOption = options.filter(
opt => value && value.some(v => v === opt.id)
)
setVal(selectedOption)
if (options.length && value?.length) {

const newVal: ListItemValue[] = []
const optionMap = new Map<string, ListItemValue>()

options.forEach(opt => {
optionMap.set(opt.id, opt)
})

value.forEach(item => {
const value = optionMap.get(item)
if (value) {
newVal.push(value)
}
})

setVal(newVal)

}
}, [options, value])

Expand All @@ -59,6 +75,10 @@ export default function StatusSelectMultiple({
}, [updateCounter])

const selectedList = val
const slicedList = val.slice(0, maxDisplay)
const rest = val.slice(maxDisplay).length

const bgOfAll = 'linear-gradient(45deg, rgba(226,40,130,1) 0%, rgba(226,40,142,1) 50%, rgba(30,235,107,1) 50%, rgba(30,235,213,1) 100%)'

return (
<div className={className}>
Expand All @@ -72,32 +92,37 @@ export default function StatusSelectMultiple({
setUpdateCounter(updateCounter + 1)
}}>
<List.Button>
{!selectedList || !selectedList.length ? <span className='text-transparent'>Option</span>: null}
{!selectedList || !selectedList.length ? <span className='text-transparent'>Option</span> : null}
<div className="flex flex-wrap items-center gap-2">
{selectedList.map(item => {
{slicedList.map(item => {
const stt = statuses.find(stt => stt.id === item.id)
const isAllOption = item.id === 'ALL' ? bgOfAll : stt?.color

return (
<div key={item.id} className="flex items-center gap-1">
<div
className="w-4 h-4 rounded cursor-pointer"
style={{
backgroundColor: stt ? stt.color : '#e5e5e5'
backgroundColor: stt ? stt.color : isAllOption,
background: isAllOption
}}></div>
<span className="status-title">{item.title}</span>
{noName ? null : <span className="status-title">{item.title}</span>}
</div>
)
})}
{rest ? <div>+{rest}</div> : null}
</div>
</List.Button>
<List.Options>
<List.Options width={200}>
{options.map(option => {
const stt = statuses.find(st => st.id === option.id)
const isAllOption = option.id === 'ALL' ? bgOfAll : stt?.color
return (
<List.Item key={option.id} value={option}>
<List.Item key={option.id} value={option} keepMeOnly={option.id === 'ALL'} >
<div className="flex items-center gap-2">
<div
className="w-4 h-4 rounded cursor-pointer"
style={{ backgroundColor: stt?.color }}></div>
style={{ backgroundColor: stt?.color, background: isAllOption }}></div>
<span>{option.title}</span>
</div>
</List.Item>
Expand Down
3 changes: 3 additions & 0 deletions packages/ui-app/app/_features/ProjectContainer/useGetTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export default function useGetTask() {
})

setTaskLoading(true)
console.log('before getting task =======================', point)
taskGetByCond(
{
title: term || undefined,
Expand All @@ -74,6 +75,7 @@ export default function useGetTask() {
)
.then(res => {
const { data, status, error } = res.data
console.log('fetch task data', data)
if (status !== 200) {
addAllTasks([])
localforage.removeItem(key)
Expand All @@ -83,6 +85,7 @@ export default function useGetTask() {

localforage.setItem(key, data)
setTimeout(() => {
console.log('update all task', data)
addAllTasks(data)
}, 300)
})
Expand Down
12 changes: 10 additions & 2 deletions packages/ui-app/app/_features/ProjectView/ProjectViewCreate.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Modal } from '@shared/ui'
import { useState } from 'react'
import { useEffect, useState } from 'react'
import { AiOutlinePlus } from 'react-icons/ai'
import ProjectViewModal from './ProjectViewModal'
import { IBoardFilter, ProjectViewProvider } from './context'
Expand All @@ -13,10 +13,18 @@ export default function ProjectViewCreate() {
const [filter, setFilter] = useState<IBoardFilter>({
date: 'this-month',
priority: 'ALL',
point: "INFINITE",
point: "-1",
statusIds: ['ALL'],
groupBy: ETaskFilterGroupByType.STATUS
})

useEffect(() => {
if (visible === false) {
setCustomView(false)
}

}, [visible])

return (
<ProjectViewProvider
value={{
Expand Down
14 changes: 0 additions & 14 deletions packages/ui-app/app/_features/ProjectView/ProjectViewModal.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
import { ProjectViewType } from '@prisma/client'
import { useState } from 'react'
import { HiOutlineMenuAlt1 } from 'react-icons/hi'
import {
HiMiniBars4,
HiOutlineBars2,
HiOutlineBars3,
HiOutlineBars3BottomLeft,
HiOutlineBars3BottomRight,
HiOutlineCalendar,
HiOutlineListBullet,
HiOutlineRectangleGroup,
HiOutlineRocketLaunch,
HiOutlineUserGroup,
HiOutlineViewColumns
} from 'react-icons/hi2'

import ProjectViewModalForm from './ProjectViewModalForm'
import { useProjectViewContext } from './context'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ export default function ProjectViewModalForm({
desc: string
}) {
const { projectId } = useParams()
const { setVisible, name: viewName, icon, setName, filter, customView } = useProjectViewContext()
const { setVisible, name: viewName, icon, setName, filter, customView, setCustomView } = useProjectViewContext()
const [loading, setLoading] = useState(false)
const { addProjectView } = useProjectViewAdd()

const hideModal = () => {
setTimeout(() => {
setLoading(false)
setVisible(false)
setCustomView(false)
setName('')
}, 500)
}
Expand Down
6 changes: 4 additions & 2 deletions packages/ui-app/app/_features/ProjectView/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface IBoardFilter {
priority: TaskPriority | 'ALL',
point: string
groupBy: ETaskFilterGroupByType
statusIds: string[]
}

interface IProjectViewContextProps {
Expand Down Expand Up @@ -39,7 +40,8 @@ const ProjectViewContext = createContext<IProjectViewContextProps>({
filter: {
date: "this-month",
priority: 'ALL',
point: "INFINITE",
point: "-1",
statusIds: ['ALL'],
groupBy: ETaskFilterGroupByType.STATUS
},
setFilter: () => { console.log(1) }
Expand All @@ -55,7 +57,7 @@ export const useProjectViewContext = () => {

const setFilterValue = (
name: keyof IBoardFilter,
val: string | ETaskFilterGroupByType
val: string | string[] | ETaskFilterGroupByType
) => {
setFilter(filter => ({ ...filter, [name]: val }))
}
Expand Down
Loading

0 comments on commit 5f91543

Please sign in to comment.