Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FE] v3.0.0 배포 #847

Merged
merged 7 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 56 additions & 68 deletions client/cypress/e2e/createEvent.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,72 +8,60 @@ beforeEach(() => {
});

describe('Flow: 랜딩 페이지에서부터 이벤트를 생성 완료하는 flow', () => {
it('랜딩페이지에서 "정산 시작하기" 버튼을 눌러 행사 이름 입력 페이지로 이동해야 한다.', () => {
cy.visit('/');
cy.get('button').contains('정산 시작하기').click();
cy.url().should('include', ROUTER_URLS.createEvent);
});

context('행사 이름 입력 페이지', () => {
beforeEach(() => {
cy.visit(ROUTER_URLS.createEvent);
});

it('행사 이름 입력 페이지에서 input이 포커싱 되어 있고, "다음" 버튼이 비활성화 되어 있어야 한다.', () => {
cy.get('input').focused();
cy.get('button').contains('다음').should('have.attr', 'disabled');
});

it('행사 이름이 1자 이상 입력된 경우 "다음" 버튼이 활성화 되고, 값이 없는 경우 "다음" 버튼이 비활성화 되어야 한다.', () => {
cy.get('input').type(CONSTANTS.eventName);
cy.get('button').contains('다음').should('not.have.attr', 'disabled');
cy.get('input').clear();
cy.get('input').should('have.value', '');
cy.get('button').contains('다음').should('have.attr', 'disabled');
});

it('행사 이름을 입력한 후 "다음" 버튼을 누르면 행사 비밀번호 설정 화면으로 이동해야 한다.', () => {
cy.get('input').type(CONSTANTS.eventName);
cy.get('button').contains('다음').click();

// 다음 버튼을 클릭하면 /create/event 경로가 아니라 /create/event/?로 가네요.. 그래서 일단 제거함.
cy.contains('비밀번호').should('exist');
});
});

context('행사 비밀번호 입력 페이지', () => {
beforeEach(() => {
cy.createEventName(CONSTANTS.eventName);
});

it('행사 비밀번호 입력 페이지에서 input이 포커싱 되어 있고, "행동 개시!" 버튼이 비활성화 되어 있어야 한다.', () => {
cy.get('input').focused();
cy.get('button').contains('행동 개시!').should('have.attr', 'disabled');
});

it('행사 비밀번호에 숫자가 아닌 입력을 할 경우 값이 입력되지 않아야 한다.', () => {
cy.get('input').type('테스트');
cy.get('input').should('have.value', '');
});

it(`행사 비밀번호에 ${RULE.maxEventPasswordLength}자리 이상 입력을 할 경우 처음 ${RULE.maxEventPasswordLength}자리만 입력되어야 한다.`, () => {
cy.get('input').type('12345');
cy.get('input').should('have.value', CONSTANTS.eventPassword);
});

it('행사 비밀번호이 1자 이상 입력된 경우 "행동 개시!" 버튼이 활성화 되고, 값이 없는 경우 "행동 개시!" 버튼이 비활성화 되어야 한다.', () => {
cy.get('input').type(CONSTANTS.eventPassword);
cy.get('button').contains('행동 개시!').should('not.have.attr', 'disabled');
cy.get('input').clear();
cy.get('input').should('have.value', '');
cy.get('button').contains('행동 개시!').should('have.attr', 'disabled');
});

it('행사 비밀번호을 입력한 후 "행동 개시!" 버튼을 누르면 행사 생성 완료 화면으로 이동해야 한다.', () => {
cy.interceptAPI({type: 'postEvent', statusCode: 200});
cy.interceptAPI({type: 'getEventName', statusCode: 200});
cy.get('input').type(CONSTANTS.eventPassword);
cy.get('button').contains('행동 개시!').click();
});
});
// it('랜딩페이지에서 "정산 시작하기" 버튼을 눌러 행사 이름 입력 페이지로 이동해야 한다.', () => {
// cy.visit('/');
// cy.get('button').contains('정산 시작하기').click();
// cy.url().should('include', ROUTER_URLS.createGuestEvent);
// });
// context('행사 이름 입력 페이지', () => {
// beforeEach(() => {
// cy.visit(ROUTER_URLS.createGuestEvent);
// });
// it('행사 이름 입력 페이지에서 input이 포커싱 되어 있고, "다음" 버튼이 비활성화 되어 있어야 한다.', () => {
// cy.get('input').focused();
// cy.get('button').contains('다음').should('have.attr', 'disabled');
// });
// it('행사 이름이 1자 이상 입력된 경우 "다음" 버튼이 활성화 되고, 값이 없는 경우 "다음" 버튼이 비활성화 되어야 한다.', () => {
// cy.get('input').type(CONSTANTS.eventName);
// cy.get('button').contains('다음').should('not.have.attr', 'disabled');
// cy.get('input').clear();
// cy.get('input').should('have.value', '');
// cy.get('button').contains('다음').should('have.attr', 'disabled');
// });
// it('행사 이름을 입력한 후 "다음" 버튼을 누르면 행사 관리자 이름 입력 화면으로 이동해야 한다.', () => {
// cy.get('input').type(CONSTANTS.eventName);
// cy.get('button').contains('다음').click();
// cy.contains('관리자의 이름').should('exist');
// });
// });
// context('행사 비밀번호 입력 페이지', () => {
// beforeEach(() => {
// cy.createEventName(CONSTANTS.eventName);
// });
// it('행사 비밀번호 입력 페이지에서 input이 포커싱 되어 있고, "행동 개시!" 버튼이 비활성화 되어 있어야 한다.', () => {
// cy.get('input').focused();
// cy.get('button').contains('행동 개시!').should('have.attr', 'disabled');
// });
// it('행사 비밀번호에 숫자가 아닌 입력을 할 경우 값이 입력되지 않아야 한다.', () => {
// cy.get('input').type('테스트');
// cy.get('input').should('have.value', '');
// });
// it(`행사 비밀번호에 ${RULE.maxEventPasswordLength}자리 이상 입력을 할 경우 처음 ${RULE.maxEventPasswordLength}자리만 입력되어야 한다.`, () => {
// cy.get('input').type('12345');
// cy.get('input').should('have.value', CONSTANTS.eventPassword);
// });
// it('행사 비밀번호이 1자 이상 입력된 경우 "행동 개시!" 버튼이 활성화 되고, 값이 없는 경우 "행동 개시!" 버튼이 비활성화 되어야 한다.', () => {
// cy.get('input').type(CONSTANTS.eventPassword);
// cy.get('button').contains('행동 개시!').should('not.have.attr', 'disabled');
// cy.get('input').clear();
// cy.get('input').should('have.value', '');
// cy.get('button').contains('행동 개시!').should('have.attr', 'disabled');
// });
// it('행사 비밀번호을 입력한 후 "행동 개시!" 버튼을 누르면 행사 생성 완료 화면으로 이동해야 한다.', () => {
// cy.interceptAPI({type: 'postEvent', statusCode: 200});
// cy.interceptAPI({type: 'getEventName', statusCode: 200});
// cy.get('input').type(CONSTANTS.eventPassword);
// cy.get('button').contains('행동 개시!').click();
// });
// });
});
2 changes: 1 addition & 1 deletion client/cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Cypress.Commands.add('interceptAPI', ({type, delay = 0, statusCode = 200}: Inter
});

Cypress.Commands.add('createEventName', (eventName: string) => {
cy.visit(ROUTER_URLS.createEvent);
cy.visit(ROUTER_URLS.createMemberEvent);
cy.get('input').type(eventName);
cy.get('button').contains('다음').click();
});
Expand Down
13 changes: 13 additions & 0 deletions client/src/apis/fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,19 @@ export const requestGet = async <T>({
return data;
};

export const requestGetWithoutResponse = async ({
headers = {},
errorHandlingStrategy,
...args
}: WithErrorHandlingStrategy<RequestMethodProps>) => {
await request({
...args,
method: 'GET',
headers,
errorHandlingStrategy,
});
};

export const requestPatch = ({headers = {}, ...args}: RequestMethodProps) => {
return request({method: 'PATCH', headers, ...args});
};
Expand Down
21 changes: 20 additions & 1 deletion client/src/apis/request/auth.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {BASE_URL} from '@apis/baseUrl';
import {ADMIN_API_PREFIX, USER_API_PREFIX} from '@apis/endpointPrefix';
import {requestPostWithoutResponse} from '@apis/fetcher';
import {requestGet, requestGetWithoutResponse, requestPostWithoutResponse} from '@apis/fetcher';
import {WithEventId} from '@apis/withId.type';

import getKakaoRedirectUrl from '@utils/getKakaoRedirectUrl';

export const requestPostAuthentication = async ({eventId}: WithEventId) => {
await requestPostWithoutResponse({
baseUrl: BASE_URL.HD,
Expand All @@ -23,3 +25,20 @@ export const requestPostToken = async ({eventId, password}: WithEventId<RequestP
},
});
};

export const requestKakaoClientId = async () => {
return await requestGet<{clientId: string}>({
baseUrl: BASE_URL.HD,
endpoint: '/api/kakao-client-id',
});
};

export const requestGetKakaoLogin = async (code: string) => {
await requestGetWithoutResponse({
baseUrl: BASE_URL.HD,
endpoint: `/api/login/kakao?code=${code}&redirect_uri=${getKakaoRedirectUrl()}`,
errorHandlingStrategy: 'errorBoundary',
});

return null;
};
36 changes: 25 additions & 11 deletions client/src/apis/request/event.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import {Event, EventId} from 'types/serviceType';
import {Event, EventCreationData, EventId, EventName, User} from 'types/serviceType';
import {WithErrorHandlingStrategy} from '@errors/RequestGetError';

import {ADMIN_API_PREFIX, USER_API_PREFIX} from '@apis/endpointPrefix';
import {requestGet, requestPatch, requestPostWithResponse, requestPut} from '@apis/fetcher';
import {requestGet, requestPatch, requestPostWithResponse} from '@apis/fetcher';
import {WithEventId} from '@apis/withId.type';

export interface RequestPostEvent {
eventName: string;
password: string;
}
export const requestPostGuestEvent = async (postEventArgs: EventCreationData) => {
return await requestPostWithResponse<EventId>({
endpoint: `${USER_API_PREFIX}/guest`,
body: {
...postEventArgs,
},
});
};

export const requestPostEvent = async ({eventName, password}: RequestPostEvent) => {
export const requestPostMemberEvent = async (eventName: EventName) => {
return await requestPostWithResponse<EventId>({
endpoint: USER_API_PREFIX,
body: {
eventName,
password,
},
});
};
Expand All @@ -28,14 +31,25 @@ export const requestGetEvent = async ({eventId, ...props}: WithEventId<WithError
};

export type RequestPatchEvent = WithEventId & {
eventOutline: Partial<Event>;
eventName: string;
};

export const requestPatchEvent = async ({eventId, eventOutline}: RequestPatchEvent) => {
export const requestPatchEventName = async ({eventId, eventName}: RequestPatchEvent) => {
return requestPatch({
endpoint: `${ADMIN_API_PREFIX}/${eventId}`,
body: {
...eventOutline,
eventName,
},
});
};

export type RequestPatchUser = Partial<User>;

export const requestPatchUser = async (args: RequestPatchUser) => {
return requestPatch({
endpoint: `/api/users`,
body: {
...args,
},
});
};
3 changes: 3 additions & 0 deletions client/src/assets/image/kakao.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ const getButtonVariantsStyle = (variants: ButtonVariants, theme: Theme) => {
}),
getHoverAndActiveBackground(theme.colors.tertiary),
],
kakao: [
css({
backgroundColor: theme.colors.kakao,
color: theme.colors.onKakao,
}),
],
};

return style[variants];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {Theme} from '@theme/theme.type';

export type ButtonSize = 'small' | 'medium' | 'semiLarge' | 'large';
export type ButtonVariants = 'primary' | 'secondary' | 'tertiary' | 'destructive' | 'loading';
export type ButtonVariants = 'primary' | 'secondary' | 'tertiary' | 'destructive' | 'loading' | 'kakao';

export interface ButtonStyleProps {
variants?: ButtonVariants;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ const getFixedButtonVariantsStyle = (variants: ButtonVariants, theme: Theme) =>
}),
getHoverAndActiveBackground(theme.colors.tertiary),
],
kakao: [
css({
backgroundColor: theme.colors.kakao,
color: theme.colors.onKakao,
}),
],
};

return style[variants];
Expand Down
1 change: 1 addition & 0 deletions client/src/components/Design/components/Icon/Icon.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const ICON_DEFAULT_COLOR: Record<IconType, IconColor> = {
heundeut: 'gray',
photoButton: 'white',
chevronDown: 'tertiary',
kakao: 'onKakao',
};

export const iconStyle = ({iconType, theme, iconColor}: IconStylePropsWithTheme) => {
Expand Down
2 changes: 2 additions & 0 deletions client/src/components/Design/components/Icon/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import InputDelete from '@assets/image/inputDelete.svg';
import Error from '@assets/image/error.svg';
import Confirm from '@assets/image/confirm.svg';
import Kakao from '@assets/image/kakao.svg';
import Trash from '@assets/image/trash.svg';
import TrashMini from '@assets/image/trash_mini.svg';
import Search from '@assets/image/search.svg';
Expand Down Expand Up @@ -41,6 +42,7 @@ export const ICON = {
),
photoButton: <PhotoButton />,
chevronDown: <ChevronDownLarge />,
kakao: <Kakao />,
} as const;

export const Icon = ({iconColor, iconType, ...htmlProps}: IconProps) => {
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/Design/components/TopNav/NavItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type {NavItemProps} from './NavItem.type';

import {useLocation, useNavigate} from 'react-router-dom';

import getDeletedLastPath from '@utils/getDeletedLastPath';
import getEventBaseUrl from '@utils/getEventBaseUrl';

import TextButton from '../TextButton/TextButton';

Expand All @@ -28,7 +28,7 @@ const NavItem = ({displayName, routePath, onHandleRouteInFunnel, noEmphasis = fa
navigate(-1);
break;
default:
navigate(`${getDeletedLastPath(location.pathname)}${routePath}`);
navigate(`/${getEventBaseUrl(location.pathname)}${routePath}`);
break;
}
};
Expand Down
7 changes: 6 additions & 1 deletion client/src/components/Design/token/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ export type ColorKeys =
| 'errorContainer'
| 'onErrorContainer'
| 'warn'
| 'complete';
| 'complete'
| 'kakao'
| 'onKakao';
export type ColorTokens = Record<ColorKeys, Color>;

// TODO: (@soha) 대괄호 사용에 대해 논의
Expand All @@ -106,6 +108,9 @@ export const COLORS: ColorTokens = {
onErrorContainer: PRIMITIVE_COLORS.pink[300],
warn: PRIMITIVE_COLORS.yellow[400],
complete: PRIMITIVE_COLORS.green[300],

kakao: '#FEE500',
onKakao: '#181600',
};

export const PRIMARY_COLORS = PRIMITIVE_COLORS.purple;
2 changes: 1 addition & 1 deletion client/src/constants/errorMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const SERVER_ERROR_MESSAGES: ErrorMessage = {
export const ERROR_MESSAGE = {
eventName: SERVER_ERROR_MESSAGES.EVENT_NAME_LENGTH_INVALID,
eventPasswordType: SERVER_ERROR_MESSAGES.EVENT_PASSWORD_FORMAT_INVALID,
memberName: SERVER_ERROR_MESSAGES.MEMBER_NAME_LENGTH_INVALID,
memberName: `이름은 ${RULE.maxMemberNameLength}자까지 입력 가능해요.`,
purchasePrice: `${RULE.maxPrice.toLocaleString('ko-kr')}원 이하의 숫자만 입력이 가능해요`,
purchaseTitle: `지출 이름은 ${RULE.maxBillNameLength}자 이하의 한글, 영어, 숫자만 가능해요`,
preventEmpty: '값은 비어있을 수 없어요',
Expand Down
2 changes: 2 additions & 0 deletions client/src/constants/queryKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const QUERY_KEYS = {
reports: 'reports',
billDetails: 'billDetails',
images: 'images',
kakaoClientId: 'kakao-client-id',
kakaoLogin: 'kakao-login',
};

export default QUERY_KEYS;
Loading
Loading