-
Notifications
You must be signed in to change notification settings - Fork 208
[1단계 - 페이먼츠] 카멜(진나영) 미션 제출합니다. #435
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
Merged
Merged
Changes from 33 commits
Commits
Show all changes
49 commits
Select commit
Hold shift + click to select a range
89dffb6
feat: 페어 프로그래밍 초기 세팅
JeLee-river b584488
docs: 미션의 기능목록, 설계 구조 등 작성
JeLee-river 54cd47d
style: 전역 스타일링 적용
JeLee-river c5aeb04
feat: Input 컴포넌트 생성
JeLee-river 6c97deb
feat: InputForm 컴포넌트 생성
JeLee-river d21b7c2
feat: 카드 번호 입력 컴포넌트 작성
JeLee-river ab65cb5
feat: 카드 유효기간 입력 컴포넌트 작성
JeLee-river 6736ff9
feat: 카드 CVC 입력 컴포넌트 작성
JeLee-river 2f38071
feat: 카드 입력 form 컴포넌트 작성
JeLee-river 9f3ca2d
refactor: InputForm이 Input을 children으로 받도록 리팩토링
JeLee-river 590cea9
style: 전역 변수로 관리하는 색상 추가
JeLee-river 6a939ca
feat: 카드 브랜드 로고 이미지 생성
JeLee-river dd0545e
style: 카드 입력 form 컴포넌트 스타일 적용
JeLee-river 99221c1
style: 기본 스타일을 초기화하는 파일 수정
JeLee-river 4c78448
style: 카드 입력 컴포넌트의 스타일 수정
JeLee-river 8b02e89
feat: 카드 정보를 입력하는 UI를 렌더링하는 함수 생성
JeLee-river a0369d1
style: 카드 정보를 입력하는 UI에 스타일 추가
JeLee-river d6e5927
style: 카드 입력 form의 스타일 조정
JeLee-river 65d9928
feat: 사용자가 입력한 카드 정보를 프리뷰에 렌더링하는 기능 구현
JeLee-river 1d09069
feat: 카드 번호와 유효기간 정보를 상태관리 하도록 코드 추가
JeLee-river 33bb1e8
refactor: 사용자 카드 정보 등록 페이지가 렌더링되도록 app 수정
JeLee-river b75a883
feat: 사용자 입력값의 예외 처리 로직 생성
JeLee-river 461a369
feat: 사용자 입력값에 대한 피드백 메시지 렌더링 로직 추가
JeLee-river b3c73c8
refactor: 유효기간 검증 로직 수정
JeLee-river b339891
feat: 카드 유효기간 검증 로직 추가
JeLee-river a5b3347
feat: 카드 CVC 검증 로직 추가
JeLee-river 5acd51b
feat: 카드 번호 검증 로직 추가
JeLee-river 34e372b
docs: 구현한 기능 목록 체크
JeLee-river 391c1b9
refactor: 상태 변경 함수의 타입 추가
JeLee-river 514e201
style: storybook에 css 적용
JeLee-river 13ff1bd
refactor: 불필요한 props 제거
JeLee-river 464572b
test: storybook 비주얼 테스트 추가
JeLee-river f92ac28
fix: 웹 배포 환경에 따라 이미지 경로 수정
dev-dino22 a208999
refactor: 불필요한 fragment 제거
dev-dino22 5f94959
refactor: 카드 정보 상수 분리
dev-dino22 d34ae3d
refactor: checkBrand 조건문 startsWith()로 가독성 개선
dev-dino22 c1bf6f8
refactor: 다시 유효한 값 입력 시 오류 스타일 삭제
dev-dino22 5ed8cc4
refactor: 유효기간 month, year로 나누고 전용 validator 분리
dev-dino22 b61f061
refactor: 전역 상태 대신 ref로 유효기간 검증 관리
dev-dino22 d476f0d
refactor: 카드 유효기간입력 컴포넌트의 inputs를 map 함수 렌더링으로 변경
dev-dino22 736fd2a
refactor: CardExpirationDateInput 의 onChangeHandler 함수/상수 분리 및 추상화
dev-dino22 eee598a
refactor: 카드프리뷰의 let 을 사용한 함수 내 상태관리에서 useMemo()훅 활용
dev-dino22 3d12de1
refactor: Input 컴포넌트에서 이제 불필요한 forwardRef 제거 및 props 전개 방식으로 변경
dev-dino22 92ee2c2
chore: Input컴포넌트 폴명 파스칼케이스 수정을 위한 중간임시 폴더명
dev-dino22 f177789
feat: input 폴더명 카멜케이스 수정
dev-dino22 7f491da
refactor: validateCardInput.ts 의 숫자문자열 검사 메서드명 수정
dev-dino22 6a493e1
refactor: validateCardInput.ts의 반환값 에러결과불리언객체로 통일
dev-dino22 337f2d1
refactor: Input 컴포넌트는 isValid 프롭을 전달받고 각 유효 상태를 사용처에서 제어하도록 변경 및 에러메세…
dev-dino22 ce26f82
chore: 불필요한 import 문 제거
dev-dino22 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| <!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
|
|
||
| <link href="../src/index.css" rel="stylesheet" /> | ||
|
|
||
| <title>Document</title> | ||
| </head> | ||
| <body></body> | ||
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,124 @@ | ||
| # react-payments | ||
|
|
||
| # 기능 목록 | ||
|
|
||
| ## 사용자 입력 | ||
|
|
||
| - [x] 사용자는 카드 번호를 입력할 수 있다. | ||
| - [x] 16자리의 입력 번호를 실시간 감지하여 알맞는 브랜드 로고를 UI에 표시한다. (Visa: 4로 시작 / MasterCard: 51~55로 시작 / 그외 로고 렌더링 x ) | ||
| - [x] 예외: 숫자만 가능 / 16자리 / 한칸에 네 자리 -> 피드백: 빨간 border & 포커스 & 밑에 피드백 문구 출력 | ||
| - [x] 사용자는 카드 유효기간을 입력할 수 있다. | ||
| - [x] 예외: 숫자만 가능 / 2자리 / 월은 1~12 까지 연도 25~99까지 / 오늘 날짜를 기준으로 유효한 기간인지 검증 -> 피드백: 빨간 border & 포커스 & 밑에 피드백 문구 출력 | ||
| - [x] 사용자는 CVC 번호를 입력할 수 있다. | ||
| - [x] 예외: 숫자만 가능 / 3자리 -> 피드백: 빨간 border & 포커스 & 밑에 피드백 문구 출력 | ||
|
|
||
| ## UI 업데이트 | ||
|
|
||
| - [x] 사용자 입력에 따라 동시에 프리뷰를 업데이트한다. | ||
| - [x] 입력할 때마다 한자리 단위로 실시간 업데이트 | ||
| - [x] 카드번호에 유효한 로고 실시간 업데이트 | ||
| - [x] 카드번호 뒷 8자리는 마스킹 처리 | ||
|
|
||
| # 테스트 목록 (Storybook) | ||
|
|
||
| ## 결제 입력 테스트 파일 | ||
|
|
||
| - ### Describe | ||
|
|
||
| - 사용자가 카드 정보를 입력 시 | ||
|
|
||
| - ### Context | ||
|
|
||
| - 사용자가 카드 번호를 입력할 경우 | ||
| - ### It | ||
|
|
||
| - 사용자가 16자리를 다 채우지 않은 채 카드번호 인풋 포커스를 이탈하면 "유효하지 않은 카드번호입니다. 16자리를 입력해주세요." 피드백을 출력한다. | ||
| - 한 칸에 4자리를 다 채우지 않은 채 다음 포커스 이동하면 "유효하지 않은 번호입니다. 4자리를 입력해주세요." 피드백을 출력한다. | ||
| - 사용자가 숫자 이외를 입력하려고 하면 "유효하지 않은 입력입니다. 숫자만 입력해주세요." 피드백을 출력한다. | ||
|
|
||
| - ### Context | ||
| - 사용자가 카드 유효 기간을 입력할 경우 | ||
| - ### It | ||
|
|
||
| - 사용자가 4자리를 다 채우지 않은 채 유효기간 인풋 포커스를 이탈하면 "유효하지 않은 카드번호입니다. 16자리를 입력해주세요." 피드백을 출력한다. | ||
| - 한 칸에 2자리를 다 채우지 않은 채 다음 포커스 이동하면 "유효하지 않은 번호입니다. 2자리를 입력해주세요." 피드백을 출력한다. | ||
| - 사용자가 숫자 이외를 입력하려고 하면 "유효하지 않은 입력입니다. 숫자만 입력해주세요." 피드백을 출력한다. | ||
| - 사용자가 현재 날짜 이전 기간을 입력할 경우 "유효하지 않은 카드입니다. 유효 기간을 확인해주세요." 피드백을 출력한다. | ||
|
|
||
| - ### Context | ||
| - 사용자가 CVC를 입력할 경우 | ||
| - ### It | ||
| - 사용자가 3자리를 다 채우지 않은 채 CVC 인풋 포커스를 이탈하면 "유효하지 않은 CVC입니다. 3자리를 입력해주세요." 피드백을 출력한다. | ||
| - 사용자가 숫자 이외를 입력하려고 하면 "유효하지 않은 입력입니다. 숫자만 입력해주세요." 피드백을 출력한다. | ||
|
|
||
| ## 카드 프리뷰 UI 테스트 파일 | ||
|
|
||
| - ### Describe | ||
| - 사용자가 카드 정보를 입력 시 | ||
| - ### Context | ||
| - 사용자가 카드 번호를 입력할 경우 | ||
| - ### It | ||
| - 카드 번호 첫 자리가 4로 시작하면 VISA 로고가 렌더링된다. | ||
| - 카드 번호 첫 자리가 51~55 로 시작하면 MasterCard 로고가 렌더링된다. | ||
| - 사용자가 카드번호를 입력할 시 실시간으로 카드 번호가 업데이트된다. | ||
| - 카드번호 뒷 8자리는 마스킹 처리하여 표시한다. | ||
| - ### Context | ||
| - 사용자가 유효 기간을 입력할 경우 | ||
| - ### It | ||
| - 사용자가 유효 기간을 입력할 시 실시간으로 카드 번호가 업데이트된다. | ||
|
|
||
| # 설계 구조 | ||
|
|
||
| ## 디렉터리 구조 | ||
|
|
||
| src/utils | ||
| src/constants | ||
| src/styles | ||
| src/components | ||
|
|
||
| src/components/abc/constants | ||
| src/components/abc/styles | ||
|
|
||
| Dom 트리구조와 비슷한 디렉터리 설계 | ||
| src/components/paymentsLayout/paymentInput/ | ||
| src/components/common | ||
|
|
||
| ## 컴포넌트 분리 | ||
|
|
||
| ```js | ||
| src/ | ||
| ├── components/ | ||
| │ ├── common/ | ||
| │ │ ├── input.ts # validator 콜백을 받아서 input 하나를 검증 | ||
| │ │ └── inputForm.ts # input 개수만큼 input 생성 + validator 전달 | ||
| │ │ | ||
| │ ├── paymentsInputPage/ | ||
| │ │ ├── paymentsInputPage.ts # 카드 정보 입력 페이지의 메인 컴포넌트 | ||
| │ │ │ | ||
| │ │ ├── cardInputForm/ # 카드 입력 폼 영역 | ||
| │ │ │ ├── cardInputForm.ts # 카드 번호, 유효기간, CVC를 포함하는 폼 컴포넌트 | ||
| │ │ │ ├── cardNumberInput/ | ||
| │ │ │ │ └── cardNumberInput.ts # 카드 번호 입력 필드 | ||
| │ │ │ ├── cardExpirationDateInput/ | ||
| │ │ │ │ └── cardExpirationDateInput.ts # 유효기간 입력 필드 | ||
| │ │ │ └── cardCVCInput/ | ||
| │ │ │ └── cardCVCInput.ts # CVC 입력 필드 | ||
| │ │ │ | ||
| │ │ └── cardPreview/ # 카드 미리보기 영역 | ||
| │ │ └── cardPreview.ts # 카드 정보 시각화 (title, description, label, inputs) | ||
| ``` | ||
|
|
||
| ## 상태 관리 | ||
|
|
||
| paymentsInputPage는 cardInputForm의 상태를 cardPreview에 반영 | ||
|
|
||
| - cardInputForm 은 paymentsInputPage의 setState 콜백을 받아 자식들(card~input 컴포넌트들) 상태를 변경 | ||
|
|
||
| - paymentsInputPage는 state를 cardPreview에 전달 | ||
| - cardPreview는 state에 따라 실시간 변경 | ||
|
|
||
| # 컨벤션 | ||
|
|
||
| ## CSS 작성 방식 | ||
|
|
||
| - Module CSS |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| :root { | ||
| --grey: #acacac; | ||
| --black: #000000; | ||
| --white: #ffffff; | ||
| --red: #ff3d3d; | ||
| --gold: #ddcd78; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| .input { | ||
| width: 100%; | ||
| border: 1px solid var(--grey); | ||
| border-radius: 4px; | ||
| color: var(--black); | ||
| padding: 12px 8px; | ||
| &::placeholder { | ||
| color: var(--grey); | ||
| } | ||
|
|
||
| &:focus { | ||
| border: 1px solid var(--black); | ||
| } | ||
| &.isNotValid { | ||
| border: 1px solid var(--red); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import { ComponentProps, Dispatch, SetStateAction, useState } from 'react'; | ||
| import styles from './Input.module.css'; | ||
|
|
||
| export interface InputProps extends Omit<ComponentProps<'input'>, 'onChange'> { | ||
| onChange: ( | ||
| event: React.ChangeEvent<HTMLInputElement>, | ||
| setState: Dispatch<SetStateAction<boolean>> | ||
| ) => void; | ||
| } | ||
|
|
||
| function Input({ | ||
| type, | ||
| onChange, | ||
| name, | ||
| id, | ||
| placeholder, | ||
| maxLength, | ||
| }: InputProps) { | ||
| const [isValid, setIsValid] = useState<boolean>(true); | ||
|
|
||
| return ( | ||
| <input | ||
| type={type} | ||
| name={name} | ||
| id={id} | ||
| placeholder={placeholder} | ||
| maxLength={maxLength} | ||
| onChange={(e) => onChange(e, setIsValid)} | ||
| className={`${styles.input} ${!isValid && styles.isNotValid} tx-md`} | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
| export default Input; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| .container { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 16px; | ||
| } | ||
|
|
||
| .inputForm { | ||
| display: flex; | ||
| justify-content: space-between; | ||
| align-items: center; | ||
| } | ||
|
|
||
| .inputContainer { | ||
| display: flex; | ||
| justify-content: space-between; | ||
| align-items: center; | ||
| gap: 10px; | ||
| } | ||
|
|
||
| .inputBox { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 8px; | ||
| } | ||
|
|
||
| label { | ||
| color: var(--black); | ||
| } | ||
|
|
||
| .titleBox { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 8px; | ||
|
|
||
| & p { | ||
| color: var(--grey); | ||
| } | ||
| } | ||
|
|
||
| .feedbackMessage { | ||
| color: var(--red); | ||
| height: 18px; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| import styles from './InputForm.module.css'; | ||
|
|
||
| export interface InputFormProps { | ||
| title: string; | ||
| label: string; | ||
| description?: string; | ||
| feedbackMessage?: string; | ||
| children: React.ReactNode; | ||
| } | ||
|
|
||
| function InputForm(props: InputFormProps) { | ||
| const { title, label, description, feedbackMessage } = props; | ||
|
|
||
| return ( | ||
| <div className={styles.container}> | ||
| <div className={styles.titleBox}> | ||
| <h3 className='tx-xl'>{title}</h3> | ||
| {description && <p className='tx-md'>{description}</p>} | ||
| </div> | ||
| <div className={styles.inputBox}> | ||
| <label className='tx-lg'>{label}</label> | ||
| <div className={styles.inputContainer}>{props.children}</div> | ||
| <p | ||
| style={ | ||
| feedbackMessage | ||
| ? { visibility: 'visible' } | ||
| : { visibility: 'hidden' } | ||
| } | ||
| className={`${styles.feedbackMessage}`} | ||
| > | ||
| {feedbackMessage} | ||
| </p> | ||
| </div> | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| export default InputForm; | ||
16 changes: 16 additions & 0 deletions
16
src/components/paymentInputPage/PaymentInputPage.module.css
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| .section { | ||
| display: flex; | ||
| width: 100%; | ||
| justify-content: center; | ||
| } | ||
| .container { | ||
| width: 390px; | ||
| height: fit-content; | ||
| display: flex; | ||
| flex-direction: column; | ||
| align-items: center; | ||
| border: 1px solid var(--grey); | ||
| border-radius: 4px; | ||
| padding: 28px; | ||
| gap: 40px; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import CardPreview from './cardPreview/CardPreview'; | ||
| import CardInputForm from './cardInputForm/CardInputForm'; | ||
| import styles from './PaymentInputPage.module.css'; | ||
| import { useState } from 'react'; | ||
|
|
||
| function PaymentInputPage() { | ||
| const [cardNumbers, setCardNumbers] = useState<string[]>([]); | ||
| const [expirationDate, setExpirationDate] = useState<string[]>([]); | ||
|
|
||
| return ( | ||
| <section className={styles.section}> | ||
| <div className={styles.container}> | ||
| <CardPreview | ||
| cardNumbers={cardNumbers} | ||
| expirationDate={expirationDate} | ||
| /> | ||
| <CardInputForm | ||
| setCardNumbers={setCardNumbers} | ||
| setExpirationDate={setExpirationDate} | ||
| /> | ||
| </div> | ||
| </section> | ||
| ); | ||
| } | ||
|
|
||
| export default PaymentInputPage; |
5 changes: 5 additions & 0 deletions
5
src/components/paymentInputPage/cardInputForm/CardInputForm.module.css
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| .cardInputForm { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 26px; | ||
| } |
24 changes: 24 additions & 0 deletions
24
src/components/paymentInputPage/cardInputForm/CardInputForm.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import { Dispatch, SetStateAction } from 'react'; | ||
| import CardCVCInput from './cardInput/CardCVCInput'; | ||
| import CardExpirationDateInput from './cardInput/CardExpirationDateInput'; | ||
| import CardNumberInput from './cardInput/CardNumberInput'; | ||
| import styles from './cardInputForm.module.css'; | ||
|
|
||
| interface CardInputFormProps { | ||
| setCardNumbers: Dispatch<SetStateAction<string[]>>; | ||
| setExpirationDate: Dispatch<SetStateAction<string[]>>; | ||
| } | ||
|
|
||
| function CardInputForm({ | ||
| setCardNumbers, | ||
| setExpirationDate, | ||
| }: CardInputFormProps) { | ||
| return ( | ||
| <div className={styles.cardInputForm}> | ||
| <CardNumberInput setCardNumbers={setCardNumbers} /> | ||
| <CardExpirationDateInput setExpirationDate={setExpirationDate} /> | ||
| <CardCVCInput /> | ||
| </div> | ||
| ); | ||
| } | ||
| export default CardInputForm; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.