Skip to content
Open
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
43 changes: 13 additions & 30 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,27 @@
"node": true,
"es6": true
},
"plugins": [
"import",
"@typescript-eslint",
"react",
"prettier"
],
"plugins": ["import", "@typescript-eslint", "react", "prettier"],
"extends": [
"airbnb",
"airbnb-typescript",
"airbnb/hooks",
"next/core-web-vitals",
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
"plugin:prettier/recommended",
"prettier"
"next/core-web-vitals"
],
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"no-console": "off",
"@typescript-eslint/no-unused-vars": "off",
"react-hooks/exhaustive-deps": "off",
//여기까지 배포를 위한 규칙제거..
"react/react-in-jsx-scope": "off",

"react/jsx-filename-extension": [
"warn",
{
"extensions": [
".ts",
".tsx"
]
"extensions": [".ts", ".tsx"]
}
],
"@typescript-eslint/camelcase": "off",
Expand All @@ -42,7 +37,6 @@
"tsx": "never"
}
],
"no-console": "error",
"react/jsx-props-no-spreading": 0,
"prettier/prettier": [
"error",
Expand All @@ -54,7 +48,6 @@
2,
{ "namedComponents": ["arrow-function", "function-declaration"] }
]
//prop spred 제한하는 속성, 코드의 가독성과 유지보수를 위해서 어떤prop을 내려주는지 명시하는것이 좋다. but 공통컴포넌트에 rest파라미터 사용을 위해 속성추가. 대안을 찾아보겠습니다!
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
Expand All @@ -65,15 +58,5 @@
},
"project": "./tsconfig.json"
},
"ignorePatterns": [
"build",
"dist",
"public"
],
"prettier/prettier": [
"error",
{
"endOfLine": "off"
}
]
}
"ignorePatterns": ["build", "dist", "public"]
}
6 changes: 5 additions & 1 deletion src/components/Calendar/MiniCalendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,18 @@ function MiniCalendar({ activityId, onDateSelect }: IMiniCalendarProps) {
const times = await fetchAvailableSchedule(newSelectedDate);

const filteredTimes = times.filter((time: IavailableTimes) => {
if (!time.date) {
return false;
}

const timeDate = new Date(time.date);
return (
timeDate.getDate() === day &&
timeDate.getFullYear() === newSelectedDate.getFullYear() &&
timeDate.getMonth() === newSelectedDate.getMonth()
);
});
console.log(filteredTimes);

onDateSelect(filteredTimes);
};

Expand Down
6 changes: 1 addition & 5 deletions src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,7 @@ function Header() {
queryFn: fetchUserData,
});

const {
data: notificationsData,
error: notificationsError,
isLoading: notificationsLoading,
} = useQuery({
const { data: notificationsData } = useQuery({
queryKey: ['userNotifications'],
queryFn: fetchNotifications,
});
Expand Down
87 changes: 47 additions & 40 deletions src/components/Input/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,56 @@
import { useState } from 'react';
import React from 'react';


interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
id: string;
placeholder: string;
error?: string;
id: string;
placeholder: string;
error?: string;
}

function Input({ id, placeholder, error, className = '', ...inputProps }: InputProps) {
const [value, setValue] = useState<string | null>(null);
const [emailError, setEmailError] = useState<string | null>(null);

const validateEmail = (email: string) => {
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/;
if (!emailRegex.test(email)) {
setEmailError('잘못된 이메일입니다.');
} else {
setEmailError(null);
}
};

const handleBlur = (value: string) => {
if (id === 'email') {
validateEmail(value);
}
};

return (
<div>
<div>
<input
className={`w-full h-[58px] text-lg text-black border ${emailError ? `border-red-ff4` : `border-black`} rounded-[5px] px-5`}
id={id}
placeholder={placeholder}
value={value || ''}
onChange={(e) => setValue(e.target.value)}
onBlur={(e) => handleBlur(e.target.value)}
autoComplete="new-password"
{...inputProps}
/>
</div>
{emailError && <p className={`text-xs text-red-ff4 px-2 pt-2`}>{emailError}</p>}
</div >
);
function Input({
id,
placeholder,
error,
className = '',
...inputProps
}: InputProps) {
const [value, setValue] = useState<string | null>(null);
const [emailError, setEmailError] = useState<string | null>(null);

const validateEmail = (email: string) => {
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/;
if (!emailRegex.test(email)) {
setEmailError('잘못된 이메일입니다.');
} else {
setEmailError(null);
}
};

const handleBlur = (value: string) => {
if (id === 'email') {
validateEmail(value);
}
};

return (
<div>
<div>
<input
className={`h-[58px] w-full border text-lg text-black ${emailError ? `border-red-ff4` : `border-black`} rounded-[5px] px-5`}
id={id}
placeholder={placeholder}
value={value || ''}
onChange={(e) => setValue(e.target.value)}
onBlur={(e) => handleBlur(e.target.value)}
autoComplete="new-password"
{...inputProps}
/>
</div>
{emailError && (
<p className={`px-2 pt-2 text-xs text-red-ff4`}>{emailError}</p>
)}
</div>
);
}

export default Input;
124 changes: 70 additions & 54 deletions src/components/Input/PwdInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,67 +6,83 @@ import IconVisibilityOff from '@/assets/icons/ic_visibility_off.svg';
import IconVisibilityOn from '@/assets/icons/ic_visibility_on.svg';
import React from 'react';


interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
id: string;
placeholder: string;
error?: string;
correct?: string;
id: string;
placeholder: string;
error?: string;
correct?: string;
}

function PwdInput({ id, placeholder, error, className = '', correct = '', ...inputProps }: InputProps) {
const [visible, setVisible] = useState(false);
const [password, setPassword] = useState<string | null>(null);
const [pwdError, setPwdError] = useState<string | null>(null);
const [PwdConfirmError, setPwdConfirmError] = useState<string | null>(null);
const type = visible ? 'text' : 'password';
function PwdInput({
id,
placeholder,
error,
className = '',
correct = '',
...inputProps
}: InputProps) {
const [visible, setVisible] = useState(false);
const [password, setPassword] = useState<string | null>(null);
const [pwdError, setPwdError] = useState<string | null>(null);
const [PwdConfirmError, setPwdConfirmError] = useState<string | null>(null);
const type = visible ? 'text' : 'password';

const validatePassword = (pwd: string) => {
if (id === "password") {
if (pwd.length < 8) {
setPwdError('8자 이상 입력해주세요.');
} else {
setPwdError(null);
}
}
else if (id === "passwordConfirm") {
if (pwd !== correct) {
setPwdConfirmError('비밀번호가 일치하지 않습니다.');
} else {
setPwdConfirmError(null);
}
}
};
const validatePassword = (pwd: string) => {
if (id === 'password') {
if (pwd.length < 8) {
setPwdError('8자 이상 입력해주세요.');
} else {
setPwdError(null);
}
} else if (id === 'passwordConfirm') {
if (pwd !== correct) {
setPwdConfirmError('비밀번호가 일치하지 않습니다.');
} else {
setPwdConfirmError(null);
}
}
};

return (
<div>
<div className='relative w-full'>
<input
className={`w-full h-[58px] text-lg text-black border ${pwdError || PwdConfirmError ? 'border-red-ff4' : 'border-black'} rounded-[5px] px-5 ${className}`}
type={type}
id={id}
placeholder={placeholder}
value={password || ''}
onChange={(e) => setPassword(e.target.value)}
onBlur={(e) => validatePassword(e.target.value)}
autoComplete="new-password"
{...inputProps}
/>
return (
<div>
<div className="relative w-full">
<input
className={`h-[58px] w-full border text-lg text-black ${pwdError || PwdConfirmError ? 'border-red-ff4' : 'border-black'} rounded-[5px] px-5 ${className}`}
type={type}
id={id}
placeholder={placeholder}
value={password || ''}
onChange={(e) => setPassword(e.target.value)}
onBlur={(e) => validatePassword(e.target.value)}
autoComplete="new-password"
{...inputProps}
/>

<button type="button" onClick={() => setVisible(!visible)}
className='absolute top-1/2 -translate-y-1/2 right-5'>
{visible ? (
<Image src={IconVisibilityOff} alt="Show" />
) : (
<Image src={IconVisibilityOn} alt="Hide" />
)}
</button>
</div>
<button
type="button"
onClick={() => setVisible(!visible)}
className="absolute right-5 top-1/2 -translate-y-1/2"
>
{visible ? (
<Image src={IconVisibilityOff} alt="Show" />
) : (
<Image src={IconVisibilityOn} alt="Hide" />
)}
</button>
</div>

{pwdError && <p className={`text-xs text-red-ff4 px-2 pt-2 ${className}`}>{pwdError}</p>}
{PwdConfirmError && <p className={`text-xs text-red-ff4 px-2 pt-2 ${className}`}>{PwdConfirmError}</p>}
</div>
);
{pwdError && (
<p className={`px-2 pt-2 text-xs text-red-ff4 ${className}`}>
{pwdError}
</p>
)}
{PwdConfirmError && (
<p className={`px-2 pt-2 text-xs text-red-ff4 ${className}`}>
{PwdConfirmError}
</p>
)}
</div>
);
}

export default PwdInput;
7 changes: 2 additions & 5 deletions src/components/Layout/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Header from '@/components/Header/Header';
import Footer from '@/components/Footer/Footer';
import SideNavCard from '@/components/SideNavCard/SideNavCard';
import Register from '@/containers/register/Register';

interface Layout {
children: React.ReactNode;
Expand All @@ -11,11 +10,9 @@ const Layout = ({ children }: Layout) => {
return (
<div className="flex flex-col bg-gray-fa">
<Header />
<div className="flex justify-center gap-[16px] desktop:gap-[24px] mt-[24px] desktop:mt-[72px] px-[24px] mobile:px-[15px] mb-[200px]">
<div className="mb-[200px] mt-[24px] flex justify-center gap-[16px] px-[24px] mobile:px-[15px] desktop:mt-[72px] desktop:gap-[24px]">
<SideNavCard />
<div className="max-w-[790px] w-full">
{children}
</div>
<div className="w-full max-w-[790px]">{children}</div>
</div>
<Footer />
</div>
Expand Down
14 changes: 10 additions & 4 deletions src/components/Main/Category.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,24 @@ import { useRouter } from 'next/router';

function Category() {
const [categoryValue, setCategoryValue] = useState<string>('');
const [sortValue, setSortValue] = useState<
'price_asc' | 'price_desc' | 'most_reviewed' | 'latest' | undefined
>(undefined);
// const [sortValue, setSortValue] = useState<
// 'price_asc' | 'price_desc' | 'most_reviewed' | 'latest' | undefined
// >(undefined);
const [sortValue, setSortValue] = useState('');
const [sortLabel, setSortLabel] = useState<string>('가격');
const [currentPage, setCurrentPage] = useState<number>(1);
const [totalItems, setTotalItems] = useState<number>(0);
const [itemsPerPage, setItemsPerPage] = useState<number>(8);
const router = useRouter();

const sortOptions = [
const sortOptions: {
label: string;
value: 'price_asc' | 'price_desc' | 'most_reviewed' | 'latest';
}[] = [
{ label: '가격 낮은순', value: 'price_asc' },
{ label: '가격 높은순', value: 'price_desc' },
{ label: '가장 많이 리뷰된', value: 'most_reviewed' },
{ label: '최신순', value: 'latest' },
];

const categoryOptions = [
Expand Down
Loading