Skip to content

Commit

Permalink
Merge pull request #110 from prgrms-fe-devcourse/77-feature/PDetailRe…
Browse files Browse the repository at this point in the history
…viewForm

77-feature/PDetailReviewForm 컴포넌트 구현
  • Loading branch information
bluedog129 authored Oct 1, 2024
2 parents 58e4ca2 + a803000 commit 70f56f3
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 7 deletions.
53 changes: 53 additions & 0 deletions src/components/PDetailReviewForm/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useRef, useEffect, useState } from 'react';
import { PDetailReviewInput } from '../PDetailReviewInput';
import * as S from './styles';

export const PDetailReviewForm = () => {
const initialReview = localStorage.getItem('review') || '';
const inputRef = useRef<HTMLTextAreaElement>(null);
const formRef = useRef<HTMLFormElement>(null);
const [isEditing, setIsEditing] = useState(false);
const [review, setReview] = useState(initialReview);

const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const form = new FormData(e.target as HTMLFormElement);
const reviewData = form.get('review') as string;
localStorage.setItem('review', reviewData);
setIsEditing(false);
};
const onChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
if (e.target instanceof HTMLTextAreaElement) setReview(e.target.value);
};
const onClickCancelButton = () => {
setIsEditing(false);
setReview(initialReview);
};
const onClickEditButton = () => setIsEditing(true);

useEffect(() => {
if (isEditing) {
inputRef?.current?.focus();
inputRef?.current?.setSelectionRange(review.length, review.length);
}
}, [inputRef, isEditing]);

return (
<S.FormContainer onSubmit={onSubmit} ref={formRef}>
<S.Label>리뷰</S.Label>
<PDetailReviewInput name="review" ref={inputRef} disabled={!isEditing} value={review} onChange={onChange} />
<S.ButtonContainer>
{isEditing ? (
<>
<S.SaveButton disabled={initialReview === review}>저장하기</S.SaveButton>
<S.CancelButton type="button" onClick={onClickCancelButton}>
취소
</S.CancelButton>
</>
) : (
<S.EditButton onClick={onClickEditButton}>수정하기</S.EditButton>
)}
</S.ButtonContainer>
</S.FormContainer>
);
};
56 changes: 56 additions & 0 deletions src/components/PDetailReviewForm/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import styled from 'styled-components';

export const FormContainer = styled.form`
display: grid;
grid-template-columns: auto 1fr;
grid-template-rows: auto auto;
gap: 15px 35px;
width: 100%;
max-width: 500px;
`;

export const Label = styled.label`
align-self: start;
margin-top: 10px;
`;

export const ButtonContainer = styled.div`
grid-column: 2;
justify-self: end;
display: flex;
gap: 10px;
`;

const Button = styled.button`
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 14px;
transition: opacity 0.2s ease;
&:disabled {
background-color: ${({ theme }) => theme.colors.gray};
cursor: not-allowed;
}
&:hover:not(:disabled) {
opacity: 0.8;
}
`;

export const SaveButton = styled(Button)`
background-color: ${({ theme }) => theme.colors.primary};
color: ${({ theme }) => theme.colors.white};
`;

export const EditButton = styled(Button)`
background-color: ${({ theme }) => theme.colors.primary};
color: ${({ theme }) => theme.colors.white};
`;

export const CancelButton = styled(Button)`
background-color: ${({ theme }) => theme.colors.white};
border: 1px solid ${({ theme }) => theme.colors.gray};
color: ${({ theme }) => theme.colors.black};
`;
18 changes: 15 additions & 3 deletions src/components/PDetailReviewInput/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import React, { forwardRef } from 'react';
import * as S from './styles';

export const PDetailReviewInput = ({ ...rest }: React.TextareaHTMLAttributes<HTMLTextAreaElement>) => {
return <S.PDetailReviewInput placeholder="공연에 대한 리뷰를 남겨주세요." {...rest} />;
};
interface PDetailReviewInputProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
defaultValue?: string;
}
export const PDetailReviewInput = forwardRef<HTMLTextAreaElement, PDetailReviewInputProps>(
({ defaultValue, ...rest }, ref) => {
return (
<S.PDetailReviewInput placeholder="공연에 대한 리뷰를 남겨주세요." ref={ref} {...rest}>
{defaultValue}
</S.PDetailReviewInput>
);
},
);

PDetailReviewInput.displayName = 'PDetailReviewInput';
12 changes: 8 additions & 4 deletions src/components/PDetailReviewInput/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ export const PDetailReviewInput = styled.textarea`
border: 1px solid ${({ theme }) => theme.colors.gray};
border-radius: 10px;
resize: none;
background-color: ${({ theme }) => theme.colors.gray};
transition: background-color 0.3s ease;
outline: none;
&::placeholder {
color: ${({ theme }) => theme.colors.text_gray};
}
&:focus {
outline: none;
background-color: ${({ theme }) => theme.colors.white};
&:placeholder-shown {
background-color: ${({ theme }) => theme.colors.gray};
&:not(:disabled) {
background-color: ${({ theme }) => theme.colors.white};
}
}
`;

0 comments on commit 70f56f3

Please sign in to comment.