Skip to content

Commit

Permalink
Merge pull request #186 from hanaro-on-and-on/feat/#151
Browse files Browse the repository at this point in the history
Feat/#151 사장님 백엔드 연동 완료
  • Loading branch information
ShinKwang2 authored Jul 9, 2024
2 parents c3e90d4 + e20a907 commit a6df471
Show file tree
Hide file tree
Showing 40 changed files with 1,351 additions and 426 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
"axios": "^1.7.2",
"clsx": "^2.1.1",
"date-fns": "^3.6.0",
"moment-timezone": "^0.5.45",
"react": "^18.3.1",
"react-calendar": "^5.0.0",
"react-datepicker": "^7.2.0",
"react-cookie": "^7.1.4",
"react-datepicker": "^7.2.0",
"react-dom": "^18.3.1",
"react-icons": "^5.2.1",
"react-kakao-maps-sdk": "^1.1.27",
Expand Down
6 changes: 5 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,23 @@ import WorkEmployeeAddComplete from './components/owner-workplace/WorkEmployeeAd
import OwnerGreeting from './pages/LandingPage/OwnerGreeting';
import OwnerAddMainAccount from './pages/LandingPage/OwnerAddMainAccount';
import LoginPage from './pages/LoginPgae/LoginPage';
import CalendarEmployee from './components/employee/CalendarEmployee';
import WorkPlaceAdd from './components/owner-workplace/WorkPlaceAdd';
import AddWorkPlace from './pages/owner/AddWorkPlace';

function App() {
return (
<>
<Routes>
<Route path='/' element={<LandingPage />} />
<Route path='hi' element={<AddWorkPlace />} />
<Route path='/login' element={<LoginPage />} />
<Route path='/test' element={<Test />} />
{/* <Route path='/ui' element={<UiTest />} /> */}
{/* <Route path='/owner/myWorkPlaces/add' element={<WorkPlaceAddPage />} /> */}
<Route path='/owner/addPlaceFirst' element={<WorkPlaceAdd />} />
<Route path='/owner/addPlaceSecond' element={<AddWorkPlace />} />
<Route path='/owner/*' element={<OwnerMainPage />}>
<Route path='test' element={<CalendarEmployee />} />
<Route path='calendar' element={<CalendarCustom />} />
<Route path='calendar/:date' element={<DateDetail />} />
<Route path='calendar/:date/add' element={<AttendanceCreate />} />
Expand Down
89 changes: 89 additions & 0 deletions src/api/apiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import employeeApi from './interfaces/employeeApi';
import ownerApi from './interfaces/ownerApi';
import userApi from './interfaces/userApi';
import { getToken } from '../utils/token';
import { EmployeeContract, Place } from '../types/contract';

class ApiClient implements employeeApi, userApi, ownerApi {
//singleton pattern
Expand Down Expand Up @@ -336,6 +337,20 @@ class ApiClient implements employeeApi, userApi, ownerApi {
return response.data;
}

// ==========================
// 알바생 - 캘린더 데이터
public async getEmployeeCalendarData(
year: number,
month: number
): Promise<EmployeeCalendarDataResponse> {
const response: BaseResponse<EmployeeCalendarDataResponse> =
await this.axiosInstance.request({
method: 'get',
url: `employee/salaries/calendar?year=${year}&month=${month}`,
});
return response.data;
}

// 사장님 - 캘린더 데이터
public async getCalendarData(
year: number,
Expand Down Expand Up @@ -398,6 +413,80 @@ class ApiClient implements employeeApi, userApi, ownerApi {
return response.data;
}

// 사장님 - 근로자 추가
public async registerEmployee(
id: number,
request: Partial<EmployeeContract>
): Promise<RegisterEmployeeResponse> {
const respnose: BaseResponse<RegisterEmployeeResponse> =
await this.axiosInstance.request({
method: 'post',
url: `/papers/${id}/employment-contracts`,
data: request,
});
return respnose.data;
}
// 사장님 - 근무 수동 추가
public async registerAttendance(
request: RegisterAttendanceManualRequest
): Promise<RegisterAttendanceManualResponse> {
const response: BaseResponse<RegisterAttendanceManualResponse> =
await this.axiosInstance.request({
method: 'post',
url: `/owner/attendances/manual`,
data: request,
});
return response.data;
}
// 사장님 - 공지 추가
public async registerNotice(
id: number,
request: RegisterNoticeRequest
): Promise<RegisterNoticeResponse> {
const response: BaseResponse<RegisterNoticeResponse> =
await this.axiosInstance.request({
method: 'post',
url: `/owner/work-places/${id}/notifications`,
data: request,
});
return response.data;
}
// 사장님 - 사업자등록번호 조회
public async validBusinessNumber(
request: ValidBusinessNumberRequest
): Promise<ValidBusinessNumberResponse> {
const response: BaseResponse<ValidBusinessNumberResponse> =
await this.axiosInstance.request({
method: 'post',
url: `/owner/work-places/valid/registration-number`,
data: request,
});
return response.data;
}
// 사장님 - 사업장 등록
public async registerWorkPlace(
request: Place
): Promise<RegisterWorkPlaceResponse> {
const response: BaseResponse<RegisterWorkPlaceResponse> =
await this.axiosInstance.request({
method: 'post',
url: `/owner/work-places`,
data: request,
});
return response.data;
}
// 사장님 - 공지 삭제
public async deleteNotice(
id: number,
noticeId: number
): Promise<DeleteNoticeResponse> {
const response: BaseResponse<DeleteNoticeResponse> =
await this.axiosInstance.request({
method: 'delete',
url: `/owner/work-places/${id}/notifications/${noticeId}`,
});
return response.data;
}
// 사장님 - 알바생 계좌 조회
public async OwnerGetEmployeeAccountInfo(
workPlaceEmployeeId: number
Expand Down
5 changes: 5 additions & 0 deletions src/api/interfaces/employeeApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ interface employeeApi {
employeeContractSign(
employmentContractId: number
): Promise<EmployeeContractSignRequest>;

getEmployeeCalendarData(
year: number,
month: number
): Promise<EmployeeCalendarDataResponse>;
}

export default employeeApi;
29 changes: 29 additions & 0 deletions src/api/interfaces/ownerApi.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { EmployeeContract, Place } from '../../types/contract';

interface ownerApi {
getCalendarData(year: number, month: number): Promise<CalendarData>;

Expand All @@ -13,6 +15,33 @@ interface ownerApi {

getNotifications(id: number): Promise<NotificationsResponse>;

// 사장님 - 근로자 추가
registerEmployee(
id: number,
request: Partial<EmployeeContract>
): Promise<RegisterEmployeeResponse>;

// 사장님 - 근로 수동 추가
registerAttendance(
request: RegisterAttendanceManualRequest
): Promise<RegisterAttendanceManualResponse>;

// 사장님 - 공지 추가
registerNotice(
id: number,
request: RegisterNoticeRequest
): Promise<RegisterNoticeResponse>;

// 사장님 - 사업자등록번호 조회
validBusinessNumber(
request: ValidBusinessNumberRequest
): Promise<ValidBusinessNumberResponse>;

// 사장님 - 사업장 등록
registerWorkPlace(request: Place): Promise<RegisterWorkPlaceResponse>;

// 사장님 - 알림 삭제
deleteNotice(workPlaceId: number, id: number): Promise<DeleteNoticeResponse>;
OwnerGetEmployeeAccountInfo(
workPlaceEmployeeId: number
): Promise<OwnerGetEmployeeAccountInfo>;
Expand Down
42 changes: 42 additions & 0 deletions src/components/employee/CalendarEmployee.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.react-calendar {
border: none !important;
width: 100% !important;
height: 70% !important;
display: flex;
flex-direction: column;
justify-content: space-around;
}

.react-calendar__navigation {
margin-top: 8px;
}

/* 요일 타일 스타일링 */
.react-calendar__month-view__weekdays {
@apply bg-hanaLightGreen text-center p-1 font-semibold rounded-md;
}

/* 요일 타일 텍스트 스타일링 */
.react-calendar__month-view__weekdays__weekday {
@apply text-sm text-white;
}

/* 날짜 타일 기본 스타일링 */
.react-calendar__tile {
@apply text-center p-2 m-1 hover:bg-blue-100 flex flex-col border border-b-2;
border-bottom: 2px solid #ccc !important;
}

/* 오늘 날짜 타일 스타일링 */
/* .react-calendar__tile--now {
@apply !bg-blue-300 !text-white;
} */

/* 선택된 날짜 타일 스타일링 .react-calendar__tile--active {
@apply !bg-yellow-100 !text-white;
} */

/* 선택할 수 없는 날짜 타일 스타일링 */
.react-calendar__tile--disabled {
@apply text-gray-400;
}
125 changes: 125 additions & 0 deletions src/components/employee/CalendarEmployee.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { useEffect, useState } from 'react';
import './CalendarEmployee.css';
import Calendar, { OnArgs } from 'react-calendar';
import 'react-calendar/dist/Calendar.css';
// import CalendarMark from './CalendarMark';
import { useNavigate } from 'react-router-dom';
import { useCalendarData } from '../../contexts/Calender-Data-Context';
import ApiClient from '../../api/apiClient';
import { parseYYYMMDD } from '../../utils/date-util';
import { useEmployeeCalendarData } from '../../contexts/Employee-Calender-Data-Context';
import CalendarMark from '../ui/CalendarMark';

type ValuePiece = Date | null;
type Value = ValuePiece | [ValuePiece, ValuePiece];

const currentDate = new Date();

const CalendarEmployee = () => {
const [value, setValue] = useState<Value>(currentDate);
const { calendarData, setCalendarData } = useEmployeeCalendarData();
const navigate = useNavigate();

console.log('🚀 CalendarCustom value:', value);

useEffect(() => {
if (value instanceof Date) {
const year = value.getFullYear();
const month = value.getMonth() + 1;
fetchData(year, month);
}
}, [value]);

const fetchData = async (year: number, month: number) => {
try {
const response = await ApiClient.getInstance().getEmployeeCalendarData(
year,
month
);
console.log('API 호출 결과:', response);
setCalendarData(response);
} catch (error) {
console.error('API 호출 실패:', error);
}
};

const onChangeCurrentDate = (args: OnArgs) => {
const { action, activeStartDate, value, view } = args;
// console.log('🚀 activeStartDate:', activeStartDate);
// console.log('🚀 view:', view);
// console.log('🚀 value:', value);
// console.log('🚀 action:', action);
setValue(activeStartDate!);
};

const onClickDate = (date: Date) => {
const localDateString = date.toLocaleDateString('en-CA'); // 'YYYY-MM-DD' 형식
navigate(`/owner/calendar/${localDateString}`);
};

const getListForDate = (date: Date) => {
const list = [];
calendarData &&
calendarData.list.map((workPlace) => {
if (
new Date(parseYYYMMDD(workPlace.attendDate)).toDateString() ===
date.toDateString()
) {
list.push({
...workPlace,
});
}
});
return list;
};

// const getEventsForDate = (date: Date) => {
// const events = [];
// calendarData.forEach((workPlace) => {
// workPlace.days.forEach((day) => {
// if (new Date(day.startTime).toDateString() === date.toDateString()) {
// events.push({
// ...day,
// workPlaceName: workPlace.workPlaceName,
// workPlaceColor: workPlace.workPlaceColor,
// });
// }
// });
// });
// return events;
// };

// 날짜 타일에 맞춤 콘텐츠를 추가한다.
const tileContent = ({ date, view }: { date: Date; view: string }) => {
if (view === 'month') {
// const events = getEventsForDate(date);
const list = getListForDate(date);
console.log(list, '>>>>>>>>>>>>>>>>>');
return (
// <div>헬로</div>
<div className='h-full w-full'>
{list.map((data) => (
<div key={`${data}`}>{data.workPlaceName}</div>
// <CalendarMark key={`${data}`} {...data} />
))}
</div>
);
}
};

return (
<div className='rounded-mdw-ful'>
<Calendar
locale='en'
className={'w-full'}
onChange={setValue}
onClickDay={onClickDate}
onActiveStartDateChange={onChangeCurrentDate}
value={value}
tileClassName={['h-28']}
tileContent={tileContent}
/>
</div>
);
};
export default CalendarEmployee;
Loading

0 comments on commit a6df471

Please sign in to comment.