Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

미래학자

23 우버 클론 코딩 (nomad coders) 본문

카테고리 없음

23 우버 클론 코딩 (nomad coders)

미래학자 2019. 6. 4. 08:24

#2.36 EditProfile Screen part One

이번에는 계정 정보 변경인데 중요하진 않지만 필요한 기능이다. 아직 뷰가 없어서 니콜라스가 미리 만들어논 뷰로 채우자.

  • src/routes/EditAccount/EditAccountPresenter.tsx

      import Button from "components/Button";
      import Form from "components/Form";
      import Header from "components/Header";
      import Input from "components/Input";
      import React from "react";
      import { MutationFn } from "react-apollo";
      import Helmet from "react-helmet";
      import styled from "../../typed-components";
    
      const Container = styled.div`
        text-align: center;
      `;
    
      const ExtendedForm = styled(Form)`
        padding: 0px 40px;
      `;
    
      const ExtendedInput = styled(Input)`
        margin-bottom: 30px;
      `;
    
      interface IProps {
        firstName: string;
        lastName: string;
        email: string;
        profilePhoto: string;
        onSubmit?: MutationFn;
        onInputChange: React.ChangeEventHandler<HTMLInputElement>;
        loading?: boolean;
      }
    
      const EditAccountPresenter: React.SFC<IProps> = ({
        firstName,
        lastName,
        email,
        profilePhoto,
        onSubmit,
        onInputChange,
        loading
      }) => (
        <Container>
          <Helmet>
            <title>Edit Account | Nuber</title>
          </Helmet>
          <Header title="Edit Account" backTo={"/"}/>
          <ExtendedForm submitFn={onSubmit}>
            <ExtendedInput
              onChange={onInputChange}
              type="text"
              value={firstName}
              placeholder="First Name"
              name="firstName"
            />
            <ExtendedInput
              onChange={onInputChange}
              type="text"
              value={lastName}
              placeholder="Last Name"
              name="lastName"
            />
            <ExtendedInput
              onChange={onInputChange}
              type="email"
              value={email}
              placeholder="Email"
              name="email"
            />
            <Button onClick={null} value={loading ? "Loading" : "Update"}/>
          </ExtendedForm>
        </Container>
      );
    
      export default EditAccountPresenter;
  • src/routes/EditAccount/EditAccountContainer.tsx

      import React from "react";
      import { RouteComponentProps } from "react-router-dom";
      import EditAccountPresenter from './EditAccountPresenter';
    interface IState {
      firstName: string;
      lastName: string;
      email: string;
      profilePhoto: string;
    }

    interface IProps extends RouteComponentProps<any> {}

    class EditAccountContainer extends React.Component<IProps, IState> {
      public state = {
        email: "",
        firstName: "",
        lastName: "",
        profilePhoto: ""
      };

      public render() {
        const { email, firstName, lastName, profilePhoto } = this.state;
        return (
          <EditAccountPresenter
            email={email}
            lastName={lastName}
            firstName={firstName}
            profilePhoto={profilePhoto}
            onInputChange={this.onInputChange}
            loading={false}
          />
        );
      }

      public onInputChange: React.ChangeEventHandler<HTMLInputElement> = event => {
        const {
          target: { name, value }
        } = event;

        this.setState({
          [name]: value
        } as any);
      };
    }

    export default EditAccountContainer;
  • src/routes/EditAccount/index.ts

      export { default } from "./EditAccountContainer";

위에서 인풋에 값을 연결을 해두었다.

#2.37 EditProfile Screen part Two

저번에 이어서 프로필을 바꿀 때 기존 프로필 값을 default 값으로 해야하는데, 이렇게 하기 위해서는 query로 데이터를 가져와서 뿌려줘야 한다.

  • src/sharedQueries.queries.ts USER_PROFILE query에서 lastName, firstName, email을 추가적으로 가져오도록 수정 했다.

      import { gql } from "apollo-boost";
    
      export const USER_PROFILE = gql`
        query userProfile {
          GetMyProfile {
            ok
            error
            user {
              profilePhoto
              fullName
              firstName
              lastName
              email
              isDriving
            }
          }
        }
      `;

변경사항이 있기 때문에 yarn codegen 으로 재생성하자.

  • src/routes/EditAccount/EditAccountContainer.tsx

      import React from "react";
      import { Query } from "react-apollo";
      import { RouteComponentProps } from "react-router-dom";
      import { USER_PROFILE } from "../../sharedQueries.queries";
      import {
        userProfile
      } from "../../types/api";
      import EditAccountPresenter from "./EditAccountPresenter";
    interface IState {
      firstName: string;
      lastName: string;
      email: string;
      profilePhoto: string;
      loading: boolean;
    }

    interface IProps extends RouteComponentProps<any> {}

    class ProfileQuery extends Query<userProfile> {}

    class EditAccountContainer extends React.Component<IProps, IState> {
      public state = {
        email: "",
        firstName: "",
        lastName: "",
        loading: true,
        profilePhoto: "",
      };

      public render() {
        const { email, firstName, lastName, profilePhoto, loading } = this.state;
        return (
          <ProfileQuery query={USER_PROFILE} onCompleted={this.updateFields}>
            {() => (
              <EditAccountPresenter
                email={email}
                firstName={firstName}
                lastName={lastName}
                profilePhoto={profilePhoto}
                onInputChange={this.onInputChange}
                loading={loading}
              />
            )}
          </ProfileQuery>
        );
      }

      public onInputChange: React.ChangeEventHandler<HTMLInputElement> = event => {
        const {
          target: { name, value }
        } = event;

        this.setState({
          [name]: value
        } as any);
      };

      public updateFields = (data: {} | userProfile) => {
        if("GetMyProfile" in data) {
          const {
            GetMyProfile: { user }
          } = data;
          if(user) {
            const { firstName, lastName, email, profilePhoto } = user;
            const loading = false;
            this.setState({
              email,
              firstName,
              lastName,
              loading,
              profilePhoto,
            } as any);
          }
        }
      }
    }

    export default EditAccountContainer;

이제 초기 값은 현재 프로필 값으로 셋팅이 된다.

#2.38 EditProfile Screen part Three

이제 업데이트하는 쿼리를 작성하고 업데이트 시켜주자.

  • src/routes/EditAccount/EditAccount.queries.ts

      import { gql } from "apollo-boost";
    
      export const UPDATE_PROFILE = gql`
        mutation updateProfile(
          $firstName: String!
          $lastName: String!
          $email: String!
          $profilePhoto: String!
        ) {
          UpdateMyProfile(
            firstName: $firstName
            lastName: $lastName
            email: $email
            profilePhoto: $profilePhoto
          ) {
            ok
            error
          }
        }
      `;

쿼리를 생성하기 위해 yarn codegen 을 실행하자.

  • src/routes/EditAccount/EditAccountContainer.ts 프로필을 업데이트 하는 UpdateProfileMutation 를 정의하고 추가해주었다. 업데이트 후에는 toast창을 띄우도록 하고, refetchQueries도 추가해서 업데이트 된 내용을 반영하도록 했다. fetchPolicy도 설정된 것을 볼 수 있다. cache가 설정되어 있기 때문에 항상 onCompleted이 발생하지 않는다. cache에서 값을 가져올 때도 onComplete가 호출되도록 수정했다.

      import React from "react";
      import { Mutation, Query } from "react-apollo";
      import { RouteComponentProps } from "react-router-dom";
      import { toast } from "react-toastify";
      import { USER_PROFILE } from "../../sharedQueries.queries";
      import {
        updateProfile,
        updateProfileVariables,
        userProfile
      } from "../../types/api";
      import { UPDATE_PROFILE } from "./EditAccount.queries";
      import EditAccountPresenter from "./EditAccountPresenter";
    interface IState {
      firstName: string;
      lastName: string;
      email: string;
      profilePhoto: string;
      loading: boolean;
    }

    interface IProps extends RouteComponentProps<any> {}

    class ProfileQuery extends Query<userProfile> {}

    class UpdateProfileMutation extends Mutation<
      updateProfile,
      updateProfileVariables
    > {}

    class EditAccountContainer extends React.Component<IProps, IState> {
      public state = {
        email: "",
        firstName: "",
        lastName: "",
        loading: true,
        profilePhoto: "",
      };

      public render() {
        const { email, firstName, lastName, profilePhoto, loading } = this.state;
        return (
          <ProfileQuery 
                    query={USER_PROFILE} 
                    onCompleted={this.updateFields}
                    fetchPolicy="cache-and-network"
                >
            {() => (
              <UpdateProfileMutation
                mutation={UPDATE_PROFILE}
                variables={{
                  email,
                  firstName,
                  lastName,
                  profilePhoto
                }}
                refetchQueries={[{query: USER_PROFILE}]}
                onCompleted={data => {
                  const { UpdateMyProfile } = data;
                  if(UpdateMyProfile.ok) {
                    toast.success('Profile updated!')
                  } else if (UpdateMyProfile.error) {
                    toast.error(UpdateMyProfile.error);
                  }
                }}
              >
                {(updateProfileMutation, { loading: updateLoading }) => (
                  <EditAccountPresenter
                    email={email}
                    firstName={firstName}
                    lastName={lastName}
                    profilePhoto={profilePhoto}
                    onInputChange={this.onInputChange}
                    loading={updateLoading || loading}
                                    onSubmit={() => updateProfileMutation()}
                  />
                )}
              </UpdateProfileMutation>
            )}
          </ProfileQuery>
        );
      }

      public onInputChange: React.ChangeEventHandler<HTMLInputElement> = event => {
        const {
          target: { name, value }
        } = event;

        this.setState({
          [name]: value
        } as any);
      };

      public updateFields = (data: {} | userProfile) => {
        if("GetMyProfile" in data) {
          const {
            GetMyProfile: { user }
          } = data;
          if(user) {
            const { firstName, lastName, email, profilePhoto } = user;
            const loading = false;
            this.setState({
              email,
              firstName,
              lastName,
              loading,
              profilePhoto,
            } as any);
          }
        }
      }
    }

    export default EditAccountContainer;

Comments