Recent Posts
Recent Comments
Link
Today
Total
05-09 06:27
관리 메뉴

채린씨의 티스토리

[GROUP-MAKER] 시작은 미약하나 끝은 창대할 여정의 세번째 회의.. 본문

Projects/GROUP-MAKER

[GROUP-MAKER] 시작은 미약하나 끝은 창대할 여정의 세번째 회의..

채린씨 2022. 10. 12. 21:16

2022년 10월 10일 ~ 11일 - 웹사이트 구조 개편, State 데이터 구조 결정 및 라우팅 완성

 

Notion: https://group-maker.notion.site/GROUP-MAKER-31fda201170345579a5228a842dfc643

 

GROUP-MAKER

- 포트폴리오에 추가할 수 있을만한 결과물을 내보자! - 과정을 꼼꼼하게 기록하자!

group-maker.notion.site

GitHub: https://github.com/Group-Maker/Group_Maker

 

GitHub - Group-Maker/Group_Maker

Contribute to Group-Maker/Group_Maker development by creating an account on GitHub.

github.com

 

 

회의 내용(변경 사항)

기존 와이어프레임

  • 유저 타입(guest, member)에 따라 접근 가능한 페이지를 제한할 것인가?
    • → 이미 로그인한 유저가 로그인/회원가입 페이지에 접근하는 것은 적절하지 않다
    • ⇒ 결론: routes 배열의 요소 객체의 accessibleUserType 프로퍼티에서 접근 가능한 유저 타입을 배열로 가지고 있자!
  • 진입 페이지와 로그인 페이지 단계에서(필요 없음에도) 데이터를 불러오는 것이 맞나?
    • → 상태를 루트 컴포넌트에서 전역으로 사용함
    • → 현재 유저의 타입을 정확히 알 수 있음
    • ⇒ 결론: 진입 페이지와 로그인 페이지 단계에서도 데이터를 불러오자!
  • 유저 타입은 어떻게 구분하는 게 맞는가?
    • → 비회원(로그인하지도 않고 게스트도 아닌 사람)과 게스트(회원)를 구분하지 않는 이유
      • 게스트의 정보를 로컬 스토리지에서 관리하고 있는데 따로 비회원 타입을 만들면서 게스트를 로그인의 일종으로 관리하는 것이 적절하지 않다고 생각함.
      • 게임에서는 흔한 방법이지만, 웹 서비스 관점에서 게스트는 로그인하지 않은 사용자로 보는 것이 타당하다고 봄.
      • 로그인하지 않아도 사용할 수 있는 앱이라는 최초 목적을 고려했을 때 게스트를 디폴트 값으로 보는 것이 적절하다고 생각함.
    • ⇒ 결론: 게스트(로그인하지 않은 사용자), 멤버(로그인한 사용자) 두 가지로 나눈다.
  • members 정보와 records 정보를 MembersAndRecords라는 하나의 페이지에서 관리하는 것이 적절한가?
    • → members 정보와 records 정보를 하나의 페이지에서 관리할 경우 해당 페이지가 하는 일을 한눈에 알 수 있는 적절한 이름을 주기가 어렵고, 하나의 페이지에서 제공하는 정보가 너무 많아진다.
    • ⇒ 결론: Manage members 페이지와 Previous records 페이지를 분리하자!
  • 기존에 MembersAndRecords 페이지에 있던 reset all data 버튼은 어디에 포함시킬 것인가?
    • → Manage members 페이지 또는 Previous records 페이지에서 가지고 있으면 둘 중에 하나의 페이지에서 해당 버튼을 눌러 모든 데이터가 삭제될 때 다른 페이지에서 보이는 정보까지 삭제되는 것이 사용자에게 혼란을 줄 수 있다.
    • ⇒ 결론: 각종 설정을 위한 별도의 setting 버튼을 만들어서 그 안에 포함시키자!
  • 최적 조 짜기 버튼과 수동 조 짜기 버튼이 따로 존재하고, 각각 다른 페이지로 연결되는 것이 적절한가?
    • → ‘조 짜기’라는 기능이 이 웹사이트의 주요 기능이므로 두 페이지로 분리되어 있는 것보다는 하나의 페이지에서 관리하는 것이 좋을 것 같다. 또, 생성할 조의 개수를 결정하는 방식과 생성된 조를 보여주는 방식을 통일하는 것이 좋을 것 같다.
    • ⇒ 결론: 최적 조 짜기 버튼과 수동 조 짜기 버튼을 MAKE NEW GROUP 버튼 하나로 합쳐서 하나의 페이지로 연결되도록 하되, 해당 페이지 안에서 AUTO GROUPING, MANUAL GROUPING 버튼을 제공하자! 또, AUTO GROUPING 결과와 MANUAL GROUPING 결과가 같은 형식으로 표현되도록 하자.
  • Intro 페이지를 가질 것인가?
    • → 우리의 서비스는 guest 유저가 핵심 타깃이기 때문에 저장되는 데이터가 기기에 종속되는지 여부를 제외하고는 guest 유저가 모든 기능을 다 사용할 수 있다. 따라서 intro라는 페이지를 따로 만들어서 guest/login이라는 선택지를 주기보다는 intro 페이지를 없앰으로써 사용자가 메인 기능을 이용하기까지의 단계와 불필요한 고민거리를 줄이자.
    • ⇒ 결론: Intro 페이지를 삭제하고, ManageMembers 페이지를 default 페이지로 하자! 기존에 Intro 페이지에서 제공하던 로그인 버튼과 웹사이트에 대한 간단한 설명은 비중을 줄여 메인 화면에서 제공하자.

회의를 통해 새롭게 수정한 와이어프레임

 

 

App.js

// import axios from 'axios';
import { Component } from './src/library/index.js';
import { SignIn, SignUp, NewGroup, Members, Records, Result, NotFound } from './src/pages/index.js';

const GUEST = 'guest';
const MEMBER = 'member';

export default class App extends Component {
  constructor() {
    super();
    // 초기 상태 뭘로 할지 생각해봐야 함
    const initialState = {
      path: '/',
      userType: GUEST,
      organization: {
        members: [],
        records: [],
      },
    };
    this.state = initialState;
    // 라우팅 관련 변수 함수 분리하는게 맞나 고민중
    this.routes = [
      { path: '/', Component: Members },
      { path: '/signin', Component: SignIn, accessibleUserType: [GUEST], redirectionPath: '/' },
      { path: '/signup', Component: SignUp, accessibleUserType: [GUEST], redirectionPath: '/' },
      { path: '/newgroup', Component: NewGroup },
      { path: '/records', Component: Records },
      { path: '/result', Component: Result },
    ];

    this.fetchState();
  }

  // 코드 더 깨끗하게 쓸 수 있을지 생각해보자!
  render = path => {
    const _path = path ?? window.location.pathname;

    try {
      const { Component, accessibleUserType, redirectionPath } =
        this.routes.find(route => route.path === _path) || NotFound;
      if (accessibleUserType && !accessibleUserType.includes(this.state.userType)) {
        const RedirectionComponent = this.routes.find(route => route.path === redirectionPath)?.Component || NotFound;
        return new RedirectionComponent().render();
      }
      return new Component().render();
    } catch (err) {
      console.error(err);
    }
  };

  navigate(e) {
    if (!e.target.matches('a')) {
      return;
    }
    e.preventDefault();

    const path = e.target.getAttribute('href');
    if (window.location.pathname === path) {
      return;
    }

    window.history.pushState(null, null, path);
    this.setState({ path });
  }

  async fetchState() {
    try {
      const response = await axios.get('/api/user');
      const { userType } = response.data;
      let organization;

      if (userType === GUEST) {
        // 로컬스토리지 깔끔하게 분리하는게 좋을듯?
        organization = localStorage.getItem('state') ?? organization;
      }
      if (userType === MEMBER) {
        // api 주소 이름 무조건 고쳐야 함 data가 뭐냐!
        // fetch하는 함수 & base_url 같은 것도 분리&정리하는게 좋을듯?
        const response = await axios.get('/api/organization');
        organization = response.data;
      }
      this.setState({ userType, organization });
    } catch (err) {
      console.error(err);
    }
  }

  setEvent() {
    return [
      {
        type: 'click',
        selector: 'window',
        handler: this.navigate,
      },
      {
        type: 'popstate',
        selector: 'window',
        handler: this.render,
      },
    ];
  }
}
  • state 데이터 구조
    • userType
      • guest: 로그인하지 않고 웹사이트를 이용하는 사용자 - 정보를 로컬 스토리지에서 가져옴
      • member: 로그인하고 웹사이트를 이용하는 사용자 - 정보를 서버에서 가져옴
    • organization
      • members: 조직의 멤버 정보
      • records: 지난 그룹 기록
  • routes 배열
    • Component: 해당 path로 접근 시 기본적으로 보여줄 컴포넌트
    • accessibleUserType:이 path에 접근 권한이 있는 있는 userType 배열
    • redirectionPath: 이 path에 접근 권한이 없는 userType이 path에 접근했을 때 redirect 해줄 path

 

 

  •  
Comments