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

AB테스트 기능 구현 #48

Merged
merged 10 commits into from
Sep 14, 2024
Merged

AB테스트 기능 구현 #48

merged 10 commits into from
Sep 14, 2024

Conversation

hoooooony
Copy link
Contributor

AB테스트 기능 구현

구현 : AB테스트 작성, 수정, 삭제, 승자 구현
문제 : 유저 수동 조절이 불가합니다.

@@ -57,6 +60,9 @@ function App() {
<Route path="/owner-request/:id" element={<OwnerRequestDetail />} />
<Route path="/member" element={<MemberList />} />
<Route path="/member/:id" element={<MemberDetail />} />
<Route path="/abtest" element={<ABTest />} />
<Route path="/abtest/:id" element={<ABTestDetail />} />
<Route path="/abtest/test" element={<ABTestTest />} />
<Route path="/review" element={<ReviewList />} />
<Route path="*" element={<h1>404</h1>} />
</Route>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드 검토 결과, 몇 가지 개선 사항을 제안합니다.

  1. 중복된 경로 확인: ABTest와 관련된 컴포넌트의 경로가 추가되었지만, 이러한 경로에 대한 중복이나 다른 경로와의 충돌이 발생하지 않는지 확인해야 합니다.
  2. 컴포넌트 명명 규칙: ABTestTest와 같은 이름은 혼동을 줄 수 있으므로 의미를 잘 전달하는 이름으로 변경하는 것이 좋습니다.

개선 사항을 아래와 같이 제안합니다:

@@ -4,7 +4,6 @@ import ABTest from 'pages/ABTest';
 import OwnerRequestList from 'pages/UserManage/OwnerRequest/OwnerRequestList';
 import OwnerRequestDetail from 'pages/UserManage/OwnerRequest/OwnerRequestDetail';
 import OwnerDetail from 'pages/UserManage/Owner/OwnerDetail';
-import ABTest from 'pages/ABTest';
+import ABTestMain from 'pages/ABTest';
 import ABTestDetail from 'pages/ABTest/components/ABTestDetail';
-import ABTestTest from 'pages/ABTest/test/test';
+import ABTestTestComponent from 'pages/ABTest/test/test';
 
         <Route path="/abtest" element={<ABTestMain />} />
         <Route path="/abtest/:id" element={<ABTestDetail />} />
-        <Route path="/abtest/test" element={<ABTestTest />} />
+        <Route path="/abtest/test" element={<ABTestTestComponent />} />

이렇게 수정함으로써 코드의 가독성을 높이고, 의도를 더 명확하게 전달할 수 있습니다.

getItem('테스트', 'test', <ControlOutlined />, [
getItem('AB 테스트', '/abtest', <ApartmentOutlined />),
getItem('AB 테스트의 테스트 페이지', '/abtest/test', <ApartmentOutlined />),
]),
];

const SideNavConatiner = styled.nav`

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드를 검토한 결과, 몇 가지 개선 사항과 오류를 발견했습니다. 다음은 주요 사항과 개선 제안입니다.

주요 사항

  1. 아이콘 이름: 기존의 SnippetsOutlined 아이콘 아래에 추가된 ApartmentOutlined가 적절한 것인지 확인이 필요합니다.
  2. 주석 없음: 코드가 품질 유지와 이해를 위해 명확한 주석이 부족합니다.
  3. 컴포넌트 명: SideNavConatiner라는 변수명에서 오타가 있습니다. 올바른 철자는 SideNavContainer입니다.

개선 제안

- const SideNavConatiner = styled.nav`
+ const SideNavContainer = styled.nav`

이 외에도 아이콘 사용 및 코드에 대한 설명을 추가하는 것을 고려할 수 있습니다. 코드를 더 명확하고 가독성 있게 만들기 위해 주석을 추가하세요.

font-weight: 700;
color: #404040;
padding: 12px 0 0 12px;
`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드를 검토해본 결과, 문법적으로 큰 오류는 없으나 스타일링 관점에서 개선할 부분이 있습니다. 현재 Container 컴포넌트는 빈 스타일을 가지고 있어 의미가 적습니다. 상위 레이아웃에 대한 기본적인 스타일을 설정하는 것이 좋겠습니다. 또한, Heading의 폰트 사이즈 및 색상을 좀 더 일관되게 유지하면 가독성이 향상될 수 있습니다.

다음은 개선사항에 대한 제안입니다:

@@ -1,10 +1,12 @@
 import styled from 'styled-components';
 
 export const Container = styled.div`
+  max-width: 1200px;
+  margin: 0 auto;
   padding: 20px;
 `;
 
 export const Heading = styled.h1`
   font-size: 36px; // 통일된 기준으로 변경
   font-weight: 700;
   color: #333; // 더 어두운 색으로 변경하여 가독성 증가
   padding: 12px 0 0 12px;
 `;

개선 사항 설명:

  • Container 컴포넌트에 최대 너비와 중앙 정렬을 추가하여 레이아웃의 일관성을 높였습니다.
  • Heading의 폰트 사이즈를 약간 키우고 색상을 조정하여 가독성을 개선했습니다.

<Divider orientation="left">이미지 (필수)</Divider>
</>
);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드에 대해 검토한 결과, 전체적으로 큰 오류는 없지만 몇 가지 개선할 점이 있습니다. 특히 React의 key prop이나 PropTypes를 사용하지 않은 부분에서 개선 여지가 있습니다.

주요 사항:

  1. CustomForm.Input 컴포넌트에 대해 name prop이 유니크하지 않을 경우, 리스트의 중복 문제가 발생할 수 있음.
  2. 코드의 가독성을 높이고 prop 유형을 명시하기 위해 PropTypes 사용 고려.

개선 제안 사항:

@@ -1,10 +1,11 @@
+import PropTypes from 'prop-types';
 
 export default function DetailForm() {
   const { required } = CustomForm.useValidate();
 
   return (
     <>
-      <CustomForm.Input name="name" label="이름" rules={[required()]} />
+      <CustomForm.Input key="name" name="name" label="이름" rules={[required()]} />
       <Divider orientation="left">이미지 (필수)</Divider>
     </>
   );
 }
 
+DetailForm.propTypes = {
+  name: PropTypes.string.isRequired,
+};

이 개선사항은 키가 필요한 경우를 대비했으며, PropTypes를 사용하여 컴포넌트의 props의 유효성을 검사하는 방법을 추가했습니다.

</CustomForm.Item>
</CustomForm>
);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

주요 사항:

  1. test_id는 폼에서 사용되지 않는데, 초기값으로 설정되어 있습니다. disabled 속성을 붙여도 불필요한 필드로 보입니다.
  2. device_id 필드는 disabled 상태이므로 사용자 입력을 받지 않습니다. 만약 이 필드를 보여주고자 한다면, disabled를 제거해야 합니다.

개선 제안 사항:

@@ -22,8 +22,6 @@
       initialValues={{
         test_id,
         device_id: data.device_id,
-        variable_name: data.variable_name,
-      }}
@@ -34,7 +32,8 @@
       <CustomForm.Input
         label="사용자 device id"
         name="device_id"
-        rules={[{ required: true, message: 'Device ID를 입력해주세요.' }]}
-        disabled
+        rules={[{ required: true, message: 'Device ID를 입력해주세요.' }]}        
+        // disabled  // 사용자 입력을 받을 필요가 있다면 주석 해제
       />
       <CustomForm.Input
         label="목표 실험군 변수"

변경 내용 요약:

  • test_id를 단순히 초기값으로 사용하는 대신 해당 필드를 제거하는 것이 좋습니다.
  • device_id 필드의 disabled 속성을 제거(또는 주석 처리)하여 사용자 입력 가능 여부를 조정합니다.

display: flex;
justify-content: space-between;
align-items: center;
`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드를 검토한 결과, 주의해야 할 점은 styled-components를 사용할 때 CSS 속성과 함께 몇 가지 추가적인 스타일링 고려사항이 있다는 것입니다. 특히, text-overflow: ellipsis; 속성이 제대로 작동하려면 부모 요소에 반드시 widthoverflow: hidden;이 설정되어 있어야 합니다.

주요 사항:

  1. Item 컴포넌트에서 텍스트가 잘리도록 하려면 display 속성도 적용해야 합니다.
  2. AroundRow 컴포넌트는 현재 잘 구성되어 있지만, 추가적인 여백이나 패딩을 고려할 수 있습니다.

개선 사항:

@@ -1,10 +1,10 @@
 export const Item = styled.div`
   width: 150px;
   text-overflow: ellipsis;
   white-space: nowrap;
-  overflow: hidden;
+  overflow: hidden;
+  display: block;  // 추가된 줄
 `;

이렇게 display: block;을 추가함으로써 text-overflow: ellipsis;가 올바르게 작동하게 됩니다. 필요에 따라 다른 스타일 속성들을 추가할 수도 있습니다.

);
}

export default NewTest;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

검토 결과, 주어진 코드에서 몇 가지 개선 사항이 있습니다. 특히, Input 컴포넌트를 사용할 때 valueonChange를 설정하는 부분에서 오류 및 개선할 점이 발견되었습니다.

주요 사항

  1. 숫자 입력 필드에서는 사용자가 입력한 값을 실시간으로 처리해야 하며, 잘못된 입력을 필터링하는 방법이 중요합니다.
  2. parseInt()를 사용할 때 적절한 기본값을 설정하여 NaN을 피할 수 있습니다.
  3. 입력값을 숫자로 변환할 때 바뀐 값을 즉시 반영하도록 구성을 개선할 필요가 있습니다.

개선 제안

+          let inputValue = e.target.value.replace(/[^0-9]/g, '');
+          onRateChange(index, parseInt(inputValue || '0', 10));
+        }}

여기서 주요 변경 사항:

  • onRateChange 호출 시, 직접 정수로 변환한 inputValue를 매개변수로 넘겨줍니다. 이를 통해 잘못된 입력 처리를 간소화하였습니다.

return { data, error, isLoading };
};

export default useGetUserListQuery;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

주요 사항:

  1. eslint-disable 주석 사용이 필요할 정도로 훅 규칙을 무시하는 것은 좋지 않습니다. 이 코드는 조건부 호출로 인해 React 훅 규칙을 어기고 있습니다.
  2. 에러 메시지가 문자열로 전달되고 있는데, 이를 Error 객체로 반환하면 더 일관성 있는 처리가 가능해집니다.

개선 제안 사항:

@@ -1,1 +1,2 @@
-/* eslint-disable react-hooks/rules-of-hooks */
+import { useEffect } from 'react';
+
@@ -10,14 +11,16 @@
   let data;
+  let error: Error | null = null; // 초기값을 null로 설정
   let isLoading;
 
-  if (name) {
+  useEffect(() => {
+    if (name) {
       const result = useGetUserByNameQuery(name);
       data = result.data;
       error = result.error;
       isLoading = result.isLoading;
-  } else if (id) {
+    } else if (id) {
       const result = useGetUserByIDQuery(id);
       data = result.data;
       error = result.error;
       isLoading = result.isLoading;
-  } else {
+    } else {
       data = undefined;
-      error = 'name 또는 id 중 하나를 제공해야 합니다.';
-      isLoading = false;
+      error = new Error('name 또는 id 중 하나를 제공해야 합니다.');
+      isLoading = false;
+    }
+  }, [name, id]);

설명:

  • 훅을 조건문 안에서 사용하는 것을 방지하기 위해 useEffect 훅을 사용하여 API 호출을 관리하도록 개선했습니다.
  • 에러 처리를 문자열 대신 Error 객체로 하여, 타입 안정성을 높였습니다. 이를 통해 에러 핸들링에 더 유연하게 대처할 수 있습니다.

)}
</S.Container>
);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드 리뷰 결과, 주된 오류는 발견되지 않았지만 개선할 사항이 있습니다. 다음은 제안하는 개선 사항입니다.

  1. Modal의 Click 핸들링: onClick={openModal} 이 Modal 컴포넌트에 제대로 적용 되지 않을 가능성이 있어, 적절한 이벤트와 동작을 확인하는 것이 좋습니다.
  2. 데이터 호출: useGetABTestsQuery 사용 시 상태 관리 또는 로딩 처리가 없는 점을 보완할 필요가 있습니다. 데이터 로딩 상태를 관리하여 사용자 경험을 개선할 수 있습니다.

개선사항을 diff 형식으로 제안합니다:

@@ -8,6 +8,7 @@ export default function ABTest() {
   const { data: abtestList } = useGetABTestsQuery({ page, limit: 10 });
+  const { isLoading } = useGetABTestsQuery({ page, limit: 10 });
   const { value: isModalOpen, setTrue: openModal, setFalse: closeModal } = useBooleanState();

   return (
@@ -16,7 +17,12 @@ export default function ABTest() {
       <CustomForm.Modal
         buttonText="생성"
         title="등록하기"
         width={900}
-        footer={null}
+        footer={!isModalOpen ? null : <S.Footer> {/* Footer 내용 추가 */} </S.Footer>}
         open={isModalOpen}
         onCancel={closeModal}
-        onClick={openModal}
+        onOk={closeModal}
+      >
+        <AddABTestModal onCancel={closeModal} />
+      </CustomForm.Modal>
+      
+      {isLoading ? (
+        <S.LoadingIndicator /> // 로딩 인디케이터 추가 
+      ) : abtestList && (
         <CustomTable
           data={abtestList.tests}
           pagination={{
             current: page,

주요 사항 및 개선 제안 요약:

  • Modal Event: Modal에서의 클릭 이벤트 문제 해결을 위해 onOk로 변경하고, 필요하면 Footer 등 추가 요소를 고려함.
  • 데이터 로딩 처리: 데이터를 불러오는 동안 로딩 스피너를 표시하여 사용자에게 정보를 제공하도록 개선.

@@ -26,6 +27,7 @@ const apiList = [
ownerRequestApi,
ownerApi,
reviewApi,
abTestApi,
];

const apiMiddleware = apiList.map((api) => api.middleware);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

주요 사항:

  1. 코드에서 abTestApi를 추가하는 것은 API 목록을 업데이트하는 올바른 방법입니다. 하지만, 추가된 import 문과 apiList에 삽입된 부분이 기존의 코드와 정렬되어 있지 않으면 가독성이 떨어질 수 있습니다.
  2. 중복된 빈 줄이나 비효율적인 import 정리를 피해야 합니다.

개선 제안:

@@ -12,6 +12,7 @@ import { menuCategoriesApi } from './api/storeMenu/category';
 import { ownerRequestApi } from './api/ownerRequest';
 import { ownerApi } from './api/owner';
 import { reviewApi } from './api/review';
+import { abTestApi } from './api/abtest';
 
 const apiList = [
   authApi,
@@ -26,6 +27,7 @@ const apiList = [
   reviewApi,
-  abTestApi,
+  abTestApi,
 ];
 
 const apiMiddleware = apiList.map((api) => api.middleware);

제안 사항 설명:

  • abTestApi의 추가는 잘 이루어졌지만, 기존 import와 일관성을 유지하면서 순서를 정리하면 가독성이 더욱 향상됩니다.
  • 추가한 API를 알맞은 위치에 배치하여 전체적으로 균형을 맞췄습니다.

@hoooooony hoooooony self-assigned this Sep 14, 2024
@hoooooony hoooooony merged commit dbd1572 into develop Sep 14, 2024
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant