Skip to content

Commit

Permalink
Feat/daygrid creation guide (#810)
Browse files Browse the repository at this point in the history
* feat: render events for month view (initial)

* refactor: code refactoring(remove duplicate method)

* fix: resolve collision events on month view

* fix: resolve exceedLeft, exceedRight on month view

* feat: apply creation guide for month view

* refactor: resolve merged conflicts

* fix: resolve grid cell info

* feat: cancel creation guide feature

* feat: apply creation guide for month view

* refactor: refactor code

* test: resolve checking types

* refactor: apply PR feedbacks

* test: resolve tests
  • Loading branch information
jungeun-cho committed May 25, 2021
1 parent 087b9ad commit 0fcb60a
Show file tree
Hide file tree
Showing 50 changed files with 1,008 additions and 111 deletions.
2 changes: 1 addition & 1 deletion apps/calendar/src/components/daygrid/cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import CellBar from '@src/components/daygrid/cellBar';
import { cls } from '@src/util/cssHelper';
import { PopupType } from '@src/modules/layerPopup';
import TZDate from '@src/time/date';
import { getPosition, getSize } from '@src/util/domutil';
import { getPosition, getSize } from '@src/util/dom';
import { ratio } from '@src/util/math';
import { Size } from '@src/controller/panel';
import { Day, toStartOfDay } from '@src/time/datetime';
Expand Down
22 changes: 22 additions & 0 deletions apps/calendar/src/components/daygrid/creationGuide.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { h, FunctionComponent } from 'preact';

import { toPercent } from '@src/util/units';
import { cls } from '@src/util/cssHelper';

interface CreationGuideProps {
left: number;
width: number;
}

const CreationGuide: FunctionComponent<CreationGuideProps> = (props) => {
const { left, width } = props;
const style = {
left: toPercent(left),
width: toPercent(width),
height: toPercent(100),
};

return <div className={cls('guide-creation')} style={style}></div>;
};

export default CreationGuide;
136 changes: 127 additions & 9 deletions apps/calendar/src/components/daygrid/dayGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import { h, FunctionComponent, Fragment } from 'preact';
import { h, FunctionComponent } from 'preact';
import { useEffect, useRef, useState } from 'preact/hooks';

import { useStore } from '@src/components/hooks/store';
import { useActions, useStore } from '@src/components/hooks/store';

import Grid from '@src/components/daygrid/grid';
import GridEvents from '@src/components/daygrid/gridEvents';
import GridWithMouse from '@src/components/daygrid/gridWithMouse';
import CreationGuide from '@src/components/daygrid/creationGuide';

import { toPercent } from '@src/util/units';
import Schedule from '@src/model/schedule';
import TZDate from '@src/time/date';
import { CalendarMonthOption } from '@t/store';
import { getSize } from '@src/util/domutil';
import { getSize } from '@src/util/dom';
import { cls } from '@src/util/cssHelper';
import { EVENT_HEIGHT, getRenderedEventViewModels } from '@src/util/gridHelper';
import { getLeftAndWidth, getRenderedEventViewModels } from '@src/util/gridHelper';
import { toEndOfDay, toStartOfDay } from '@src/time/datetime';
import { PopupType } from '@src/modules/layerPopup';
import { GridGuideInfo } from '@t/components/daygrid/creationGuide';
import { GridGuideCreationInfo } from '@t/components/daygrid/gridWithMouse';

const TOTAL_PERCENT_HEIGHT = 100;

Expand All @@ -21,6 +27,8 @@ interface DayGridProps {
calendar: TZDate[][];
appContainer: { current: HTMLDivElement };
events?: Schedule[];
useCreationPopup?: boolean;
getMousePositionData?: (e: MouseEvent) => MousePositionData | null;
}

function useGridHeight() {
Expand All @@ -34,12 +42,113 @@ function useGridHeight() {
return { ref, height };
}

function useCreationGuide(useCreationPopup = false) {
const [creationGuide, setCreationGuide] = useState<GridGuideCreationInfo | null>(null);
const [popupFlag, setPopupFlag] = useState(false);

const { show, hide } = useActions('layerPopup');

const onOpenCreationPopup = (guide: GridGuideCreationInfo) => {
if (useCreationPopup) {
const { start, end } = guide;

// @TODO: popupRect 계산 필요
show({
type: PopupType.creation,
param: {
start,
end,
isAllDay: true,
popupRect: {
width: 474,
height: 272,
left: 102.695,
top: 257,
},
close: () => {
onGuideCancel();
setPopupFlag(false);
},
},
});

if (!popupFlag) {
setPopupFlag(true);
}
}
};

const onGuideStart = (guide: GridGuideCreationInfo | null) => {
setCreationGuide(guide);
};
const onGuideEnd = (guide: GridGuideCreationInfo | null) => {
setCreationGuide(guide);

if (guide) {
onOpenCreationPopup(guide);
} else if (!guide && popupFlag) {
hide();
}
};
const onGuideChange = (guide: GridGuideCreationInfo) => {
setCreationGuide(guide);
};
const onGuideCancel = () => setCreationGuide(null);

return {
creationGuide,
onGuideStart,
onGuideEnd,
onGuideChange,
onGuideCancel,
};
}

function renderCreationGuide(
creationGuide: GridGuideCreationInfo,
cells: TZDate[],
narrowWeekend: boolean
) {
const { start, end } = creationGuide;
const { left, width } = getLeftAndWidth(start, end, cells, narrowWeekend);

return width > 0 ? <CreationGuide {...creationGuide} left={left} width={width} /> : null;
}

function getGridInfoList(calendar: TZDate[][]): GridGuideInfo[][] {
return calendar.map<GridGuideInfo[]>((week) =>
week.map<GridGuideInfo>((day) => {
const start = toStartOfDay(day);
const end = toEndOfDay(start);

return {
start,
end,
};
})
);
}

const DayGrid: FunctionComponent<DayGridProps> = (props) => {
const { options, calendar = [], appContainer } = props;
const {
options,
calendar = [],
appContainer,
useCreationPopup = false,
getMousePositionData = () => null,
} = props;
const { visibleWeeksCount, workweek, startDayOfWeek, narrowWeekend } = options;

const { ref, height } = useGridHeight();

const {
creationGuide,
onGuideStart,
onGuideChange,
onGuideEnd,
onGuideCancel,
} = useCreationGuide(useCreationPopup);

const rowHeight =
TOTAL_PERCENT_HEIGHT / Math.max(visibleWeeksCount === 0 ? 6 : visibleWeeksCount, 1);

Expand All @@ -53,10 +162,18 @@ const DayGrid: FunctionComponent<DayGridProps> = (props) => {

const { schedule: monthScheduleTheme } = theme.month;
const eventHeight = parseFloat(monthScheduleTheme.height);
const gridInfoList = getGridInfoList(calendar);

return (
<Fragment>
{calendar.map((week, index) => {
<GridWithMouse
onGuideStart={onGuideStart}
onGuideChange={onGuideChange}
onGuideEnd={onGuideEnd}
onGuideCancel={onGuideCancel}
gridInfoList={gridInfoList}
getMousePositionData={getMousePositionData}
>
{calendar.map((week, rowIndex) => {
const { viewModels, gridDateEventModelMap } = getRenderedEventViewModels(
week,
dataStore,
Expand All @@ -65,7 +182,7 @@ const DayGrid: FunctionComponent<DayGridProps> = (props) => {

return (
<div
key={`dayGrid-events-${index}`}
key={`dayGrid-events-${rowIndex}`}
className={cls('month-week-item')}
style={{ height: toPercent(rowHeight) }}
ref={ref}
Expand All @@ -91,11 +208,12 @@ const DayGrid: FunctionComponent<DayGridProps> = (props) => {
eventHeight={eventHeight}
className={cls('weekday-schedules')}
/>
{creationGuide ? renderCreationGuide(creationGuide, week, narrowWeekend) : null}
</div>
</div>
);
})}
</Fragment>
</GridWithMouse>
);
};

Expand Down
4 changes: 2 additions & 2 deletions apps/calendar/src/components/daygrid/grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ const Grid: FunctionComponent<GridProps> = (props) => {

return (
<div className={cls('grid')} style={style} ref={container}>
{calendar.map((date, index) => {
{calendar.map((date, columnIndex) => {
const dayIndex = date.getDay();
const { width, left } = grids[index];
const { width, left } = grids[columnIndex];
const ymd = toFormat(toStartOfDay(date), 'YYYYMMDD');

return (
Expand Down
8 changes: 6 additions & 2 deletions apps/calendar/src/components/daygrid/gridEvents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@ const GridEvents: FunctionComponent<Props> = ({
name,
className,
}) => {
const filteredViewModels = events.filter(isWithinHeight(height, eventHeight));
const headerHeight = 31; // @TODO: 테마에서 값 가져와서 설정
// @TODO: 테마에서 값 가져와서 설정
const headerHeight = 31;
const eventTopMargin = 2;
const filteredViewModels = events.filter(
isWithinHeight(height - headerHeight, eventHeight + eventTopMargin)
);

const dayEvents = filteredViewModels.map((viewModel) => (
<GridEvent
Expand Down
Loading

0 comments on commit 0fcb60a

Please sign in to comment.