Skip to content

๐Ÿ“‹๋‹น์ง,์—ฐ์ž๊ด€๋ฆฌ ํ”„๋กœ๊ทธ๋žจ "๋‹น์—ฐํ•˜์ง€"

Notifications You must be signed in to change notification settings

hahahaday12/Annual-Duty-Program

ย 
ย 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

FE_Client

๐Ÿปโ€โ„ ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

๊ฐœ๋ฐœ ๊ธฐ๊ฐ„ : 2023. 07. 24 ~ 2023. 08. 10
> ์œ ์ €์šฉ ๋ฐฐํฌ ์‚ฌ์ดํŠธ : ๋‹น์—ฐํ•˜์ง€
> ๊ด€๋ฆฌ์ž์šฉ ๋ฐฐํฌ ์‚ฌ์ดํŠธ : ๋‹น์—ฐํ•˜์ง€ ๊ด€๋ฆฌ์ž์šฉ
> ์œ ์ € ๋ ˆํฌ์ง€ํ† ๋ฆฌ : ์œ ์ €
> ๊ด€๋ฆฌ์ž ๋ ˆํฌ์ง€ํ† ๋ฆฌ : ๊ด€๋ฆฌ์ž
> ๋ฐฑ์—”๋“œ ๋ ˆํฌ์ง€ํ† ๋ฆฌ : ๋ฐฑ์—”๋“œ

๐ŸŒŸํ˜„์žฌ nextJs ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ค‘์ž…๋‹ˆ๋‹ค.
๊ธฐ๊ฐ„ : 2023.11.20 ~ 2023.11.25์ผ ๐ŸŒŸ

๐Ÿ“š STACKS

Config

Development

Deployment

๐Ÿ’ฌ Communication


โš™ ํ”„๋กœ์ ํŠธ ์„ค๊ณ„

use case

image

๐Ÿ–ฅ ํŽ˜์ด์ง€ ๋ณ„ ํ™”๋ฉด

๐Ÿง™๐Ÿปโ€โ™‚๏ธ ๋กœ๊ทธ์ธ, ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€ ๊ตฌ์„ฑ

๋กœ๊ทธ์ธ ํŽ˜์ด์ง€
ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€
ํ”„๋กœํ•„ ์ˆ˜์ • ํŽ˜์ด์ง€
๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ • ํŽ˜์ด์ง€



๐Ÿง™๐Ÿปโ€โ™€๏ธ Side Bar - ๋„ค๋น„๊ฒŒ์ด์…˜ ํŽ˜์ด์ง€ ๊ตฌ์„ฑ

ํ™ˆ ํŽ˜์ด์ง€
์—ฐ์ฐจ ์‹ ์ฒญ ํŽ˜์ด์ง€
๋‹น์ง ์‹ ์ฒญ ํŽ˜์ด์ง€
๋‚ด ์ผ์ •๋ณด๊ธฐ ํŽ˜์ด์ง€



๐Ÿง™๐Ÿป ๊ด€๋ฆฌ์ž ๊ถŒํ•œ ํŽ˜์ด์ง€ ๊ตฌ์„ฑ

๊ด€๋ฆฌ์ž ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€
์œ ์ € ๋ฆฌ์ŠคํŠธ ํŽ˜์ด์ง€
์—ฐ์ฐจ ์š”์ฒญ ๋ฆฌ์ŠคํŠธ ํŽ˜์ด์ง€
์—ฐ์ฐจ ๋ฆฌ์ŠคํŠธ ํŽ˜์ด์ง€
๋‹น์ง ์š”์ฒญ ๋ฆฌ์ŠคํŠธ ํŽ˜์ด์ง€
๋‹น์ง ๋ฆฌ์ŠคํŠธ ํŽ˜์ด์ง€

ERD


๐Ÿ”ฅ 1์ฐจ ๋ฆฌํŒฉํ† ๋ง

-> ๋‚ด๊ฐ€ ์„ ํƒํ•œ ๋‚ ์งœ์ค‘ ์—ฐ์ฐจ ์‹ ์ฒญ ๋‚ ์งœ๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
-> ์—ฐ์ฐจ, ๋‹น์ง ๋ฐ์ดํ„ฐ ํ•ฉ์ณ์„œ ์ถœ๋ ฅ
-> ์ค‘๋ณต ์ฝ”๋“œ customhook ๋งŒ๋“ค์–ด์„œ ํ•ด๊ฒฐ
-> profile contexts ์ œ๊ฑฐํ›„ recoil์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„
-> ์œ ์ € ์ •๋ณด์—์„œ ๋‚จ์€์—ฐ์ฐจ๋ฅผ ํ‘œ์‹œํ• ๋•Œ userinfo api๋ฅผ ์‚ฌ์šฉํ•จ. header์—์„œ ์‚ฌ์šฉ์ค‘์ž„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์ค‘๋ณตํ•ด์„œ api์‚ฌ์šฉ. ๋”ฐ๋ผ ์ƒํƒœ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ recoil์„ ์‚ฌ์šฉํ•˜์—ฌ header์—์„œ user์ •๋ณด์˜ ๋‚จ์€์—ฐ์ฐจ ๊ฐ’์„ store์— ์ €์žฅ


โœจ ํ”„๋กœ์ ํŠธ ๋‹ด๋‹น ๊ธฐ๋Šฅ

๐ŸŽˆ 1) ํ™ˆ, ๋ฉ”์ธ ํŽ˜์ด์ง€


โœ…๋‚ด๊ฐ€ ์‹ ์ฒญํ•œ ์—ฐ์ฐจ, ๋‹น์ง ์กฐํšŒ
- ๊ฐ๊ฐ ์—ฐ์ฐจ, ๋‹น์ง์— ๋Œ€ํ•œ ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑํ›„, restApi ๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ๊ฐ์˜ ๋ฐ์ดํ„ฐ ์กฐํšŒ.

โœ…๋‚ด๊ฐ€ ์‹ ์ฒญํ•œ ์—ฐ์ฐจ, ๋‹น์ง ์ทจ์†Œ
- ์„ ํƒํ•œ ์•„์ดํ…œ์— ๋Œ€ํ•œ type, id๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›๊ณ , ์กฐ๊ฑด์‹์„ ํ†ตํ•˜์—ฌ type ์— ๋งž๋Š” ์„ ํƒํ•œ ์‚ญ์ œ ํ•จ์ˆ˜ ํ˜ธ์ถœ. ํ•ด๋‹น ์‚ญ์ œ ํ•จ์ˆ˜์— ์„ ํƒํ•œ ์•„์ดํ…œid๋ฅผ ์ „๋‹ฌํ›„ ์„œ๋ฒ„ ์ƒํƒœ๊ฐ’์— ๋”ฐ๋ฅธ ์—…๋ฐ์ดํŠธ ๋ฐ์ดํ„ฐ ์กฐํšŒ.

โœ…๋ชจ๋“  ์œ ์ €์˜ ์—ฐ์ฐจ, ๋‹น์ง ์ผ์ • ์กฐํšŒ
- ์ฒ˜์Œ ํŽ˜์ด์ง€ mount ์‹œ ์ƒ์„ฑํ•œ customHook useCalendarData์„ ํ†ตํ•ด ๋ชจ๋“  ์œ ์ € ๋ฐ์ดํ„ฐ ์กฐํšŒ.

-> Promise.all์„ ์‚ฌ์šฉํ•˜์—ฌ, ์บ˜๋ฆฐ๋”์— ์ถœ๋ ฅ๋˜์•ผ ํ•˜๋Š” ์—ฐ์ฐจ, ๋‹น์ง์˜ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋น„๋™๊ธฐ ์ž‘์—…์„ ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌํ•จ. ๊ฐ๊ฐ์˜ Promise๋Š” ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋˜๋ฏ€๋กœ ํ•œ Promise์˜ ์™„๋ฃŒ๋ฅผ ๋‹ค๋ฅธ Promise์— ๋Œ€๊ธฐํ•˜์ง€ ์•Š๊ณ  ๋™์‹œ์— ์‹คํ–‰๋˜๊ฒŒํ•จ.
๋”ฐ๋ผ, ๋น„๋™๊ธฐ ์ž‘์—…์„ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•จ์œผ๋กœ์จ ์„ฑ๋Šฅ ํ–ฅ์ƒ์ด ๋จ.
โ†’ ์—ฐ์ฐจ, ๋‹น์ง์˜ restApi๋ฅผ ๋™์‹œ์— ํ˜ธ์ถœํ•˜๋Š” ํ•˜๋Š” ์ฝ”๋“œ์˜ ์ค‘๋ณต์„ ์ตœ์†Œํ™” ํ•˜๊ธฐ ์œ„ํ•ด customhook ์ƒ์„ฑ (์•„๋ž˜ ๐Ÿ“‚useCalendarData.tsx ์ฝ”๋“œ ์ฐธ๊ณ )

๐ŸŒŸRefectoring๐ŸŒŸ
-> ์ƒํƒœ๊ฐ’์— ๋”ฐ๋ฅธ ๋ฒ„ํŠผ ์ƒ‰์ƒ ์ ์šฉ

๐Ÿ’ป๊ตฌํ˜„์ฝ”๋“œ

๐Ÿ“‚dutyContainer.tsx

(์ด์ „ ์ฝ”๋“œ ์ƒ๋žต)
import { StatusBox, CancelBox } from '@/styles'

return(
<DutyListBox>
  {datalist(dutyDataList).map(el => (
    <DutyList key={el.id}>
      <h2>๐Ÿ“Œ {extractDate(el.dutyDate)}</h2>
      <StatusBox status={el.status}>
        {convertStatusToText(el.status)}
      </StatusBox>
      <CancelBox
        onClick={() => deleteButton('๋‹น์ง', el.id)}
        status={el.status}>
        {mainTexts.dutyCancel}
      </CancelBox>
    </DutyList>
  ))}
</DutyListBox>
)

๐Ÿ“‚styleCommon.tsx

export const StatusBox = styled.div<{ status: string }>`
  width: 70px;
  border-radius: 5px;
  position: absolute;
  right: 110px;
  font-size: 12px;
  padding: 9px;
  padding-left: 13px;
  color: #ffff;

  background-color: ${({ status }) => {
    switch (status) {
      case 'PENDING':
        return '#7752FE' // ์Šน์ธ ๋Œ€๊ธฐ ์ƒํƒœ์ผ ๋•Œ ๋ฐฐ๊ฒฝ์ƒ‰
      case 'APPROVE':
        return '#F6635C' // ์Šน์ธ ์™„๋ฃŒ ์ƒํƒœ์ผ ๋•Œ ๋ฐฐ๊ฒฝ์ƒ‰
      case 'REJECT':
        return '#B31312' // ์Šน์ธ ๊ฑฐ์ ˆ ์ƒํƒœ์ผ ๋•Œ ๋ฐฐ๊ฒฝ์ƒ‰
      default:
        return 'lightgray' // ๊ธฐ๋ณธ ๋ฐฐ๊ฒฝ์ƒ‰
    }
  }};
`

export const CancelBox = styled(StatusBox)`
  right: 20px;
  background-color: #212a3e;
  padding-left: 25px;
  cursor: pointer;
`

โ†’ ์ƒํƒœ๊ฐ’์ด ์ถœ๋ ฅ๋˜๋Š” ๋ฒ„ํŠผ, ์ทจ์†Œ ๋ฒ„ํŠผ ์˜ ์Šคํƒ€์ผ์„ ๊ณตํ†ต ์ปดํฌ๋„ŒํŠธํ™” ํ•˜์˜€์Œ.
๋”ฐ๋ผ, StatusBox๋Š” { status }์˜ ๊ฐ’์„ props๋กœ ๋ฐ›์•„ ์กฐ๊ฑด์‹์œผ๋กœ ๊ทธ์— ๋”ฐ๋ฅธ ๋ฒ„ํŠผ ์ƒ‰์ƒ์„ ์ง€์ • ํ•˜์˜€์Œ. ์ดํ›„ ํ•ด๋‹น ์Šคํƒ€์ผ ์ปดํฌ๋„ŒํŠธ๋ฅผ import ํ•˜์—ฌ ์‚ฌ์šฉํ•จ.

โ†’ ์Šคํƒ€์ผ ๊ณตํ†ต ์ปดํฌ๋„ŒํŠธํ™”๋กœ ์„œ๋กœ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์—๋„ ์‰ฝ๊ฒŒ ๋ฐ˜์˜ํ• ์ˆ˜ ์žˆ๊ณ , css-in-js์˜ ํŠน์ง•์„ ๊ฐ€์ง„ styled-components ์˜ ์žฅ์ ์„ ํ™œ์šฉํ•˜์—ฌ ์ƒํƒœ๊ฐ’์„ props๋กœ ๋ฐ›์•„์„œ ์‚ฌ์šฉํ• ์ˆ˜ ์žˆ์—ˆ์Œ.

๐ŸŒŸ๋ฆฌํŒฉํ† ๋ง ํ›„


๐ŸŽˆ 2) ๋‚ด ์ผ์ • ๋ณด๊ธฐ ํŽ˜์ด์ง€


โœ… ๋‚ด๊ฐ€ ์‹ ์ฒญํ•œ ๋‹น์ง, ์—ฐ์ฐจ ์บ˜๋ฆฐ๋” ์กฐํšŒ
-> ์บ˜๋ฆฐ๋” ์กฐํšŒ customHook ์„ ์‚ฌ์šฉํ•ด ์กฐํšŒ ๊ธฐ๋Šฅ ๊ตฌํ˜„.

-> customHook ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ๋”์šฑ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ•˜์˜€๊ณ , ๊ฐ€๋…์„ฑ์ด ํ–ฅ์ƒ๋˜๋„๋ก ๊ตฌํ˜„. ๊ฒฐ๊ณผ์ ์œผ๋กœ ์ฝ”๋“œ 52์ค„ โ†’ 19์ค„๋กœ ๊ฐ์†Œํ•จ. ์ดํ›„ ์ดˆ๊ธฐ ๋กœ๋”ฉ์†๋„ 4์ดˆ -> 0.7์ดˆ ๊ฐœ์„ 



๐Ÿ’ป์ˆ˜์ • ํ›„ ์ฝ”๋“œ

๐Ÿ“‚useCalendarData.tsx

export const useCalendarData = (
  fetchDataFunction1: Promise<AxiosResponse>,
  fetchDataFunction2: Promise<AxiosResponse>,
  getMyTitle: (item: ItemUsername) => string,
  CalDate: number
) => {
  const [viewDrow, setViewDrow] = useState<Item[]>([
    {
      title: '',
      start: '',
      end: '',
      status: '',
      type: '',
      username: ''
    }
  ])

  useEffect(() => {
    Promise.all([fetchDataFunction1, fetchDataFunction2])
      .then(([data1, data2]) => {
        const processedData1 = data1.data.response.map(
          item =>
            ({
              title: getMyTitle(item),
              start: new Date(item.startDate).toISOString(),
              end: new Date(item.endDate).toISOString(),
              type: 'ANNUAL',
              status: ''
            }) as Item
        )

        const processedData2 = data2.data.response.map(
          item =>
            ({
              ...item,
              title: getMyTitle(item),
              date: new Date(item.dutyDate),
              type: 'DUTY',
              status: ''
            }) as Item
        )
        const combinedData = [...processedData1, ...processedData2]
        setViewDrow(combinedData)
      })
      .catch(error => {
        console.error('error', error)
      })
  }, [CalDate])

  return { viewDrow }
}

โ†’ ์บ˜๋ฆฐ๋” ์ผ์ • ์กฐํšŒ customHook ์ƒ์„ฑ

๐Ÿ“‚ Schedule.tsx

export const Schedule = () => {
  const [CalDate, setCalDate] = useState<number>(2023)

  const { viewDrow } = useCalendarData(
    MyAnnualList(CalDate.toString()),
    MyDutyList(CalDate.toString()),
    getMyTitleWithStatus,
    CalDate
  )


  return (
    <Outermost>
      <Rectangle>
        <BarBox>
          <ScheduleBarone>
            <p>{commonTexts.annualText}</p>
          </ScheduleBarone>
          <ScheduleBartwo>
            <p>{commonTexts.dutyText}</p>
          </ScheduleBartwo>
        </BarBox>
        <CalendarCommon viewDrow={viewDrow}/>
      </Rectangle>
    </Outermost>
  )
}

๐ŸŽˆ 3) ์—ฐ์ฐจ/ ๋‹น์ง ์‹ ์ฒญ ํŽ˜์ด์ง€


โœ… ์—ฐ์ฐจ, ๋‹น์ง ์‹ ์ฒญ ๋ชจ๋‹ฌ -> ํด๋ฆญํ•œ ๋ฒ„ํŠผ type์„ setSelectedModal ์— ์ €์žฅํ•˜์—ฌ selectedModal ์—…๋ฐ์ดํŠธ.

์กฐ๊ฑด์‹์„ ํ†ตํ•˜์—ฌ selectedModal === 'ANNUAL_MODALโ€™ ์ผ์‹œ ํ•ด๋‹น ํƒ€์ž…์— ๋งž๋Š” ๋ชจ๋‹ฌ ์ปดํฌ๋„ŒํŠธ <AnnualModal/> ์ด ๋‚˜ํƒ€๋‚ ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„.

๐Ÿ’ป๊ตฌํ˜„ ์ฝ”๋“œ

(์ƒ๋žต)
const handleModalClick = info => {
    let dateSelect = new Date(info.date)
    dateSelect.setHours(9, 0, 0, 0)
    if (dateSelect.getDay() === 0 || dateSelect.getDay() === 6) {
      alert('ํ† ์š”์ผ ๋˜๋Š” ์ผ์š”์ผ์€ ์„ ํƒํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.')
      return false
    }

    const dupuleData = data.filter((item: DataItem) => {
      if (item.type === 'ANNUAL') {
        const startDay = item.start
        const endDay = item.end
        startDay.setHours(9, 0, 0, 0)
        endDay.setHours(9, 0, 0, 0)
        if (
          dateSelect >= startDay &&
          dateSelect <= endDay &&
          item.username === username
        ) {
          return item
        }
      } else {
        const dutyDate = item.date
        dutyDate.setHours(9, 0, 0, 0)
        if (dateSelect === dutyDate && item.username === username) {
          return item
        }
      }
      return false
    })

    console.log(dupuleData)
    if (dupuleData.length > 0) {
      alert('์ด๋ฏธ ํ•ด๋‹น ๋‚ ์งœ์— ์‹ ์ฒญํ•œ ์—ฐ์ฐจ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.')
      return false
    }

    const today = new Date()
    today.setHours(0, 0, 0, 0) //์‹œ๊ฐ„ ๋ถ„ ์ดˆ ์ดˆ๊ธฐํ™”

    if (dateSelect < today) {
      alert('์˜ค๋Š˜ ๋‚ ์งœ ์ด์ „์€ ์„ ํƒํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.')
      return
    }
    viewDrow.find(item => {
      const start = new Date(item.start)
      const end = new Date(item.end)
      if (!start || !end) {
        return false
      }
      const inRange =
        dateSelect.getTime() >= start.getTime() &&
        dateSelect.getTime() <= end.getTime()
      return inRange
    })
    setSelectedModal(
      selectedButton === 'ANNUAL' ? 'ANNUAL_MODAL' : 'DUTY_MODAL'
    )
    setSelectedDate(dateSelect)
    return false
  }

-> ์กฐ๊ฑด์‹์„ ํ†ตํ•˜์—ฌ 1๊ฐœ์ด์ƒ์˜ ์—ฐ์ฐจ, ๋‹น์ง์ด ์‹ ์ฒญ ๋˜์–ด์žˆ์œผ๋ฉด "์‹ ์ฒญ ์—ฐ์ฐจ ์กด์žฌ" ๋ผ๋Š” ์ƒํƒœ๊ฐ’์„ ์ถœ๋ ฅ.
-> ์‹ ์ฒญ restApi ๋ฅผ ํ†ตํ•ด ์„ ํƒํ•œ ๋‚ ์งœ์˜ ์—ฐ์ฐจ๋ฅผ ์‹ ์ฒญํ•˜๋„๋ก ๊ตฌํ˜„ํ•˜์˜€์œผ๋ฉด ์‹ ์ฒญํ›„ ๊ฒฐ๊ณผ๊ฐ’ ์—…๋ฐ์ดํŠธ .

โœ… ์—ฐ์ฐจ, ๋‹น์ง ์œ ์ € ๋ฐ์ดํ„ฐ
-> ์—ฐ์ฐจ, ๋‹น์ง ๋ฒ„ํŠผ ํด๋ฆญ์‹œ ๊ฐ type์— ๋งž๋Š” restApi ํ˜ธ์ถœ.

๐Ÿ’ป๊ตฌํ˜„ ์ฝ”๋“œ

const searchData = () => {
    if (calendarRef.current) {
      if (selectedButton === 'ANNUAL') {
        allAnnualList(CalDate.toString())
          .then(data => {
            const returnDatalist = data.data.response
            const modifiedReturnDatalist = returnDatalist.map(item => ({
              title: getTitleWithStatus(item),
              username: item.username,
              start: new Date(item.startDate),
              end: new Date(item.endDate),
              type: 'ANNUAL'
            }))
            setViewDrow(modifiedReturnDatalist)
            setData(modifiedReturnDatalist)
          })
          .catch(error => {
            console.error(error)
          })
      } else {
        allDutyList(CalDate.toString())
          .then(data => {
            const returnDatalist = data.data.response
            const modifiedReturnDatalist = returnDatalist.map(item => ({
              ...item,
              title: getTitleWithStatus(item),
              username: item.username,
              date: new Date(item.dutyDate),
              type: 'DUTY'
            }))
            setViewDrow(modifiedReturnDatalist)
            setData(modifiedReturnDatalist)
          })
          .catch(error => {
            console.error(error)
          })
      }
    } else {
      console.log('๋…„๋„๋ฅผ ์ฐพ์„์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.')
    }
  }

โœจ ํ”„๋กœ์ ํŠธ ๊ณ ์ฐฐ


๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ ํŒ€์› ์—ญํ• 

์•ˆ์ค‘ํ›„ ์ด์ •ํ™˜ ๊น€ํ•˜์€
์•ˆ์ค‘ํ›„ ์ด์ •ํ™˜ ๊น€ํ•˜์€
GitHub ํŒ€์žฅ
์ดˆ๊ธฐ ๊ฐœ๋ฐœ ์„ธํŒ…
ํ”„๋กœํ•„ ์ˆ˜์ •,
๋กœ๊ทธ์ธ, ํšŒ์›๊ฐ€์ž…,
Header, ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ •
๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€
(์—ฐ์ฐจ/๋‹น์ง ์Šน์ธ ํŽ˜์ด์ง€,
์—ฐ์ฐจ/๋‹น์ง ์‹ ์ฒญ ํŽ˜์ด์ง€,
๊ด€๋ฆฌ์ž - ์ „์ฒด ์œ ์ € / ํšŒ์›๊ฐ€์ž… ์š”์ฒญ ๋ฆฌ์ŠคํŠธ ํŽ˜์ด์ง€ )
์—ฐ์ฐจ/๋‹น์ง ์‚ฌ์šฉ์ž ํŽ˜์ด์ง€
(๋ฉ”์ธํŽ˜์ด์ง€(๋‚ด๊ฐ€ ์‹ ์ฒญํ•œ ๋‹น์ง, ์—ฐ์ฐจ ๋…ธ์ถœ/ ์ „์ฒด ์œ ์ € ์ผ์ • ๋…ธ์ถœ/ ์‹ ์ฒญํ•œ ์—ฐ์ฐจ,๋‹น์ง ์ทจ์†Œ),
๋‚ด ์ผ์ •๋ณด๊ธฐ ํŽ˜์ด์ง€,
์—ฐ์ฐจ/๋‹น์ง ์‹ ์ฒญ ํŽ˜์ด์ง€)

๐ŸŽˆ ์ž‘์—… ์ง„ํ–‰

1) Notion

-> ๊ทธ๋ผ์šด๋“œ ๋ฃฐ, ์ปค๋ฐ‹ ์ปจ๋ฒค์…˜, api ๋ฌธ์„œ ๋“ฑ ํ”„๋กœ์ ํŠธ์—์„œ ํ•„์š”ํ•œ๊ฒƒ๋“ค์„ ๊ธฐ๋กํ•ด๋‘์—ˆ์Šต๋‹ˆ๋‹ค.

โœ… TodoList ๋ฌธ์„œํ™” ๊ธฐ๊ฐ„์ •ํ•ด์„œ ๊ธฐ๋Šฅ ๊ตฌํ˜„

image

โœ… Api ๋ช…์„ธ์„œ ์ •๋ฆฌ

image

โœ… ๋ฐ์ผ๋ฆฌ ์Šคํฌ๋Ÿผ ํšŒ์˜๋ก ์ž‘์„ฑ

image

2) Github

๊นƒํ—ˆ๋ธŒ ์ „๋žต Github Flow

-> develop branch ์ƒ์„ฑ.
-> develop branch ์—์„œ ๊ฐ์ž ์ด๋ฆ„์˜ branch ์ƒ์„ฑ.
-> ๊ฐ์ž branch ์—์„œ ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ์ด ์™„๋ฃŒ๋˜๋ฉด develop branch ๋กœ PR ์ƒ์„ฑ.
-> ๊นƒํ—ˆ๋ธŒ ๋‹ด๋‹น์ž๊ฐ€ ์˜ฌ๋ผ์˜จ Pull request ํ™•์ธํ›„ develop branch ๋กœ merge.
-> ๋ชจ๋“  ๊ธฐ๋Šฅ ๊ตฌํ˜„ ์™„๋ฃŒํ›„ ์ตœ์ข…์ ์œผ๋กœ develop branch ๋ฅผ master branch ๋กœ merge.


1๏ธโƒฃ ์œ ์ €/๊ด€๋ฆฌ์ž ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€

  • localStorageํ† ํฐ๊ฐ’์„ ํ†ตํ•ด ๋กœ๊ทธ์ธ ์œ ์ € ํŒ๋ณ„ / ๋น„๋กœ๊ทธ์ธ ์œ ์ € ๋กœ๊ทธ์ธ ์œ ์ €์šฉ ํŽ˜์ด์ง€ ์ง„์ž… ์ฐจ๋‹จ / ๋กœ๊ทธ์ธ ์œ ์ € ๋กœ๊ทธ์ธ,ํšŒ์›๊ฐ€์ž…,๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ • ๋“ฑ ๋น„๋กœ๊ทธ์ธ ์œ ์ €์šฉ ํŽ˜์ด์ง€ ๋ถ„๋ฆฌ
  • ๊ด€๋ฆฌ์ž๊ฐ€ ์Šน์ธ์„ ํ–ˆ์„ ๊ฒฝ์šฐ์—๋งŒ ํšŒ์›๊ฐ€์ž…ํ•œ ์•„์ด๋”” ์‚ฌ์šฉ๊ฐ€๋Šฅ

2๏ธโƒฃ ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€

  • ์ด๋ฉ”์ผ ์ค‘๋ณต์ฒดํฌ API๋ฅผ ํ†ตํ•ด ์ด๋ฉ”์ผ ์ค‘๋ณต์ฒดํฌ ํ›„ ํšŒ์›๊ฐ€์ž… ๊ฐ€๋Šฅ
  • ๋น„๋ฐ€๋ฒˆํ˜ธ(์ •๊ทœ์‹์„ ํ†ตํ•œ ์œ ํšจํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ ํŒ๋ณ„)

3๏ธโƒฃ ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ • ํŽ˜์ด์ง€

  • ์ด๋ฉ”์ผ ์ž…๋ ฅ์‹œ ์ด๋ฉ”์ผ์„ ํ†ตํ•ด ์ž„์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ฐœ๊ธ‰

4๏ธโƒฃ ์ „์ฒด ํ™ˆํŽ˜์ด์ง€

  • fullCalendar ์—ฐ๋™ํ›„ ๋ชจ๋“  , ์—ฐ์ฐจ ๋‹น์ง ๋ฐ์ดํ„ฐ ์กฐํšŒ
  • ์‹ ์ฒญ ๋ถ„๋ฅ˜์— ๋”ฐ๋ฅธ ์ด๋ฒคํŠธ ์ƒ‰ ํ‘œ์‹œ
  • ๋‚ด๊ฐ€ ์‹ ์ฒญํ•œ ์—ฐ์ฐจ ์‹ ์ฒญ ํ˜„ํ™ฉ ๋ฐ์ดํ„ฐ ์กฐํšŒ
  • ๋‚ด๊ฐ€ ์‹ ์ฒญํ•œ ๋‹น์ง ์‹ ์ฒญ ํ˜„ํ™ฉ ๋ฐ์ดํ„ฐ ์กฐํšŒ
  • ์—ฐ์ฐจ, ๋‹น์ง ์‹ ์ฒญ ์ทจ์†Œํ›„ fullCalendar ์—…๋ฐ์ดํŠธ
  • ์—‘์…€๋กœ ๋‹ค์šด๋ฐ›๊ธฐ ํด๋ฆญ์‹œ ๋ถ„๋ฅ˜(์—ฐ์ฐจ, ๋‹น์ง)์— ๋”ฐ๋ผ ์—‘์…€ ๋‹ค์šด๋กœ๋“œ
  • ์—ฐ์ฐจ/ ๋‹น์ง ๋ฒ„ํŠผ ํด๋ฆญ์‹œ ํŽ˜์ด์ง€ ์ด๋™

5๏ธโƒฃ ํ”„๋กœํ•„ ์ˆ˜์ • ํŽ˜์ด์ง€

  • ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์ˆ˜์ •/์‚ญ์ œ
  • ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ(์˜์–ด ๋Œ€๋ฌธ์ž, ์˜์–ด ์†Œ๋ฌธ์ž, ์ˆซ์ž, ํŠน์ˆ˜๋ฌธ์ž๋ฅผ ๋ชจ๋‘ ํฌํ•จ (8๊ธ€์ž ์ด์ƒ)) && ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ

6๏ธโƒฃ ๋‚ด ์ผ์ •๋ณด๊ธฐ ํŽ˜์ด์ง€

  • ํ˜„์žฌ ์‹ ์ฒญํ•œ ์—ฐ์ฐจ, ๋‹น์ง ๋ฐ์ดํ„ฐ ์กฐํšŒ

7๏ธโƒฃ ์—ฐ์ฐจ/๋‹น์ง ์‹ ์ฒญ ํŽ˜์ด์ง€

  • ์—ฐ์ฐจ ์‹ ์ฒญ, ๋‹น์ง ์‹ ์ฒญ ๋ฒ„ํŠผ์— ๋”ฐ๋ผ ๋ฐ์ดํ„ฐ ๋‹ค๋ฅด๊ฒŒ ์กฐํšŒ
  • ์—ฐ์ฐจ,๋‹น์ง ์‹ ์ฒญ ๋‚ ์งœ ํด๋ฆญ์‹œ ์—ฐ์ฐจ ์‹ ์ฒญ ๋ชจ๋‹ฌ ์ƒ์„ฑ
  • ๋ชจ๋‹ฌ์ฐฝ์—์„œ ๋‚ ์งœ ์„ ํƒํ›„ ๋“ฑ๋ก์‹œ ์กฐ๊ฑด๊ฐ’์— ๋”ฐ๋ผ ์ด๋ฏธ ์‹ ์ฒญ๋œ ๋‚ ์งœ ๋“ฑ๋ก ๋ถˆ๊ฐ€.

8๏ธโƒฃ ๊ด€๋ฆฌ์ž - ์ „์ฒด ์œ ์ € / ํšŒ์›๊ฐ€์ž… ์š”์ฒญ ๋ฆฌ์ŠคํŠธ ํŽ˜์ด์ง€

  • ํ† ํฐ ๊ฐ’์ด ์—†์œผ๋ฉด ๋กœ๊ทธ์ธํŽ˜์ด์ง€๋กœ ์ด๋™

  • ์‚ฌ์šฉ์ž ์ธก ํšŒ์›๊ฐ€์ž… ์š”์ฒญ ๋ฆฌ์ŠคํŠธ๋กœ ์ถœ๋ ฅ

  • ์‚ฌ์šฉ์ž ์ธก ํšŒ์›๊ฐ€์ž…์‹œ ๊ด€๋ฆฌ์ž ์Šน์ธ ๊ธฐ๋Šฅ

  • ์ „์ฒด ๊ฐ€์ž…๋œ ์œ ์ € ๋ฆฌ์ŠคํŠธ ์ถœ๋ ฅ

    • ์œ ์ € ๋ฆฌ์ŠคํŠธ : ์„ฑ๋ช…, ์•„์ด๋””, ์ž…์‚ฌ์ผ, ์ž”์—ฌ ์—ฐ์ฐจ
    • ๋ฆฌ์ŠคํŠธ๋Š” ์ž…์‚ฌ์ผ ๊ธฐ์ค€์œผ๋กœ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ

9๏ธโƒฃ ๊ด€๋ฆฌ์ž - ์—ฐ์ฐจ/๋‹น์ง ์Šน์ธ ํŽ˜์ด์ง€

  • ์—ฐ์ฐจ

    • ์—ฐ์ฐจ ๋ฆฌ์ŠคํŠธ : ์„ฑ๋ช…, ์•„์ด๋”” , ์‚ฌ์œ , ์‹ ์ฒญ์ผ, ์‹œ์ž‘์ผ, ์ข…๋ฃŒ์ผ
    • ๋ฆฌ์ŠคํŠธ๋Š” ์‹œ์ž‘์ผ ๊ธฐ์ค€์œผ๋กœ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ
    • ์ถ”๊ฐ€์ ์œผ๋กœ ์‹ ์ฒญ์ผ, ์‹œ์ž‘์ผ, ์ข…๋ฃŒ์ผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ ๊ธฐ๋Šฅ ์ถ”๊ฐ€
  • ๋‹น์ง

    • ๋‹น์ง ๋ฆฌ์ŠคํŠธ : ์„ฑ๋ช…, ์•„์ด๋””, ์‹ ์ฒญ์ผ, ๋‹น์ง์ผ
    • ๋ฆฌ์ŠคํŠธ๋Š” ๋‹น์ง์ผ ๊ธฐ์ค€์œผ๋กœ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ
    • ์ถ”์ ์œผ๋กœ ์‹ ์ฒญ์ผ, ๋‹น์ง์ผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ ๊ธฐ๋Šฅ ์ถ”๊ฐ€
  • ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ

    • ์ „์ฒด ๋ฆฌ์ŠคํŠธ ๊ฒ€์ƒ‰
    • ์‚ฌ์šฉ์ž ์„ฑ๋ช…์„ ํ†ตํ•œ ๊ฒ€์ƒ‰
    • ๋…„, ์›”์„ ํ†ตํ•œ๊ฒ€์ƒ‰

๐Ÿ”Ÿ ๊ด€๋ฆฌ์ž - ์—ฐ์ฐจ/๋‹น์ง ๋ฆฌ์ŠคํŠธ ํŽ˜์ด์ง€

  • ์—ฐ์ฐจ

    • ์š”์ฒญ ๋ฆฌ์ŠคํŠธ : ์„ฑ๋ช…, ์•„์ด๋””, ์‹ ์ฒญ์ผ, ์‹œ์ž‘์ผ, ์ข…๋ฃŒ์ผ, ์Šน์ธ์—ฌ๋ถ€
    • ๋ฆฌ์ŠคํŠธ๋Š” ์‚ฌ์šฉ์ž๋“ค์ด ์‹ ์ฒญํ•œ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ
    • ์Šน์ธ์—ฌ๋ถ€์— ์Šน์ธ ๊ธฐ๋Šฅ๊ณผ ๊ฑฐ์ ˆ ๊ธฐ๋Šฅ
  • ๋‹น์ง

    • ์š”์ฒญ ๋ฆฌ์ŠคํŠธ : ์„ฑ๋ช…, ์•„์ด๋””, ์‹ ์ฒญ์ผ, ๋‹น์ง์ผ, ์Šน์ธ์—ฌ๋ถ€
  • ๊ณตํ†ต

    • ์Šน์ธ์‹œ ์‚ฌ์šฉ์ž์ธก์—์„œ ์Šน์ธ ํ™•์ธ ๊ฐ€๋Šฅ
    • ๊ฑฐ์ ˆ์‹œ ์‚ฌ์šฉ์ž์ธก์—์„œ ๊ฑฐ์ ˆํ™•์ธ ๊ฐ€๋Šฅ

About

๐Ÿ“‹๋‹น์ง,์—ฐ์ž๊ด€๋ฆฌ ํ”„๋กœ๊ทธ๋žจ "๋‹น์—ฐํ•˜์ง€"

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 98.1%
  • HTML 1.1%
  • JavaScript 0.8%