Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…-breath-connect into develop
  • Loading branch information
sy-paik committed Nov 17, 2023
2 parents fd269d7 + 4c9fceb commit f2edc59
Show file tree
Hide file tree
Showing 10 changed files with 263 additions and 292 deletions.
File renamed without changes.
3 changes: 3 additions & 0 deletions src/assets/sprite/spriteSheet.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 21 additions & 11 deletions src/components/Profile/ProfileForm.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import React from 'react';
import Input from '../common/Input/Input';
import Button from '../common/Button/Button';
import ProfileImage from './ProfileImage';
import { useFieldController } from '../../hook/useFieldController';
import { useForm } from 'react-hook-form';
import { PATTERN, MESSAGE } from '../../constants/validation';
import useImageUpload from '../../hook/useImageUpload';

const ProfileForm = ({ accountname, isError, message, handleInputImage, userEmail, userPassword, signup }) => {
const ProfileForm = ({ accountname, isError, message, userEmail, userPassword, signup }) => {

const { control, getValues, setValue, handleSubmit, formState: { errors } } = useForm({
const { control, getValues, handleSubmit, formState: { errors } } = useForm({
mode:'onBlur',
defaultValues: {
username: '',
Expand All @@ -16,6 +18,8 @@ const ProfileForm = ({ accountname, isError, message, handleInputImage, userEmai
}
})

const { image, previewImage, handleImage } = useImageUpload();

const usernameController = useFieldController('username', control, {
required: MESSAGE.USERNAME.REQUIRED,
pattern: {
Expand All @@ -40,21 +44,27 @@ const ProfileForm = ({ accountname, isError, message, handleInputImage, userEmai
}

const introController = useFieldController('intro', control, {});

const handleImage = (e) => {
const file = e.target.files[0];
setValue('image', file);
handleInputImage(file);
};

const onSubmit = (data) => {
if(!errors.username?.message && !errors.accountname?.message && !message)
signup(data, userEmail, userPassword);
if (!errors.username?.message && !errors.accountname?.message && !message) {
const userData = {
username: data.username,
email: userEmail,
password: userPassword,
accountname: data.accountname,
intro: data.intro || '',
image: image || '',
};
signup(userData);
}
};


return (
<form onSubmit={handleSubmit(onSubmit)}>

<ProfileImage
previewImage={previewImage} handleImage={handleImage}
/>
<Input
label='사용자 이름'
id='username'
Expand Down
63 changes: 63 additions & 0 deletions src/components/Profile/ProfileImage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React from 'react';
import styled, { css } from 'styled-components';
import AddImg from '../../assets/sprite/img-btn.svg';
import AddDarkImg from '../../assets/sprite/img-btn-dark.svg';
import BasicProfileImg from '../../assets/images/basic-profile-l.svg';

const ProfileImage = ({ previewImage, handleImage }) => {
return (
<>
<Label htmlFor="image" >
<Image src={previewImage ? previewImage : BasicProfileImg} alt="사용자 프로필 이미지" />
</Label>
<ImageInput
type="file"
accept="image/png, image/jpg, image/jpeg"
id="image"
onChange={handleImage}
/>
</>
)
}

export default ProfileImage;

const Label = styled.label`
display: block;
position: relative;
width: 11rem;
height: 11rem;
margin: 3.5rem auto 5.5rem;
border: 1px solid ${({ theme }) => theme.colors.placeHolderColor};
border-radius: 50%;
cursor: pointer;
&::after {
content: '';
display: block;
position: absolute;
right: 0;
bottom: 0;
width: 3.6em;
height: 3.6rem;
background: url(${AddImg}) no-repeat center / 3.6rem 3.6rem;
z-index: 2;
${({ isDarkMode }) => isDarkMode && css`
background: url(${AddDarkImg}) no-repeat center / 3.6rem 3.6rem;
`}
}
`

const Image = styled.img`
width: 100%;
height: 100%;
border-radius: 50%;
object-fit: cover;
`

const ImageInput = styled.input`
position: absolute;
width: 0.1rem;
height: 0.1rem;
z-index: -1000rem;
`
2 changes: 1 addition & 1 deletion src/constants/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ export const MESSAGE = {
ACCOUNTNAME: {
REQUIRED: '계정 ID를 입력해주세요',
PATTERN: '영문, 숫자, 특수문자 ., _ 만 입력해주세요'
}
},
}
58 changes: 58 additions & 0 deletions src/hook/useImageUpload.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { useState } from 'react';
import { useMutation } from 'react-query';
import { postUploadProfile } from '../api/auth';
import imageCompression from 'browser-image-compression';

const useImageUpload = () => {
const [previewImage, setPreviewImage] = useState('');
const [image, setImage] = useState('');

const uploadImage = useMutation('uploadImage', postUploadProfile, {
onSuccess: (res) => {
console.log(res);
setImage(process.env.REACT_APP_API_URL + res.filename);
},
onError: (error) => {
console.log(error);
}
});

const handleImage = async (e) => {
const file = e.target.files[0];
const allowedExtensions = ['jpg', 'gif', 'png', 'jpeg', 'bmp', 'tif', 'heic'];
const fileExtension = file.name.split('.').pop().toLowerCase();

if (allowedExtensions.includes(fileExtension)) {
try {
const options = {
maxSizeMB: 1,
maxWidthOrHeight: 800,
useWebWorker: true,
};

const compressedImage = await imageCompression(file, options);
const compressedFile = new File([compressedImage], compressedImage.name, {
type: compressedImage.type,
});

const imgData = new FormData();
imgData.append('image', compressedFile);
await uploadImage.mutate(imgData);

const reader = new FileReader();
reader.readAsDataURL(compressedFile);
reader.onload = () => {
setPreviewImage(reader.result);
};
} catch (error) {
console.error(error);
}
} else {
alert('유효하지 않은 파일 형식입니다.');
}
};

return { image, previewImage, handleImage };
};

export default useImageUpload;
65 changes: 65 additions & 0 deletions src/hook/useValid.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React, { useState, useEffect } from 'react';

export default function useValid(formData) {
const [messages, setMessages] = useState({
email: '',
password: ''
});
const [isValid, setIsValid] = useState({
email: false,
password: false
});

useEffect(() => {
if (formData.email) {
const emailRegex = /^[a-zA-Z0-9+-\_.]+@[a-zA-Z0-9-]+\.[a-zAZ0-9-.]+$/;
if (!emailRegex.test(formData.email)) {
setMessages((prevMessages) => ({
...prevMessages,
email: '이메일의 형식이 올바르지 않습니다 😥'
}));
setIsValid({ ...isValid, email: false });
} else {
setMessages((prevMessages) => ({
...prevMessages,
email: ''
}));
setIsValid({ ...isValid, email: true });
}
} else {
setMessages((prevMessages) => ({
...prevMessages,
email: ''
}));
setIsValid({ ...isValid, email: false });
}
}, [formData.email]);

useEffect(() => {
if (formData.password) {
const passwordRegex =
/^(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&])[A-Za-z\d$@$!%*#?&]{6,}$/;
if (!passwordRegex.test(formData.password)) {
setMessages((prevMessages) => ({
...prevMessages,
password: '영문+숫자+특수기호 조합으로 6자리 이상 입력해주세요'
}));
setIsValid({ ...isValid, password: false });
} else {
setMessages((prevMessages) => ({
...prevMessages,
password: ''
}));
setIsValid({ ...isValid, password: true });
}
} else {
setMessages((prevMessages) => ({
...prevMessages,
password: ''
}));
setIsValid({ ...isValid, password: false });
}
}, [formData.password]);

return { messages, setMessages, isValid, setIsValid };
}
2 changes: 1 addition & 1 deletion src/pages/LoginPage/SnsLoginPage/SnsLoginPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const SnsLoginPage = () => {
const isDarkMode = useRecoilValue(isDarkModeState);
return (
<Container>
<Title>Sns 로그인 페이지</Title>
<Title>SNS 로그인 페이지</Title>
<Main>
<LogoSection>
<LogoImage src={isDarkMode ? SnsLogoDark : SnsLogo} alt="들숨날숨 로고" />
Expand Down
Loading

0 comments on commit f2edc59

Please sign in to comment.