new-client/src/components/Profile.tsx

Summary

Maintainability
D
2 days
Test Coverage
import React, { FunctionComponent, useContext, useEffect, useState } from 'react';
import { observer } from 'mobx-react-lite';
import { Link } from 'react-router-dom';
import {
  Flex,
  CloseButton,
  Heading,
  FormControl,
  FormLabel,
  FormHelperText,
  Input,
  Radio,
  RadioGroup,
  HStack,
  VStack,
  Button,
  useToast
} from '@chakra-ui/react';
import { ServerContext } from './ServerContext';
import { Theme } from '../types/notifications';
import { rootUrl } from '../lib/urls';

const Profile: FunctionComponent = () => {
  const toast = useToast();
  const { profileStore, userStore } = useContext(ServerContext);
  const [name, setName] = useState<string>('');
  const [email, setEmail] = useState<string>('');
  const [nick, setNick] = useState<string>('');

  useEffect(() => {
    profileStore.fetchProfile();
  }, [profileStore]);

  useEffect(() => {
    setName(profileStore.profile.name);
    setEmail(profileStore.profile.email);
    setNick(userStore.myNick);
  }, [profileStore.profile.email, profileStore.profile.name, userStore.myNick]);

  const handleSave = async (type: 'name' | 'email' | 'nick') => {
    const value = type === 'name' ? name : type === 'email' ? 'email' : 'nick';
    const { success, errorMsg } = await profileStore.updateProfile(type, value);

    const capitalizedType = `${type.substr(0, 1).toUpperCase()}${type.substr(1)}`;

    toast({
      title: success ? 'Saved' : 'Failed to save',
      description: success
        ? `${capitalizedType} updated successfully.`
        : `Failed to update ${type}. Reason: ${errorMsg}`,
      status: success ? 'success' : 'error',
      duration: 3000,
      isClosable: true
    });
  };

  return (
    <Flex width="100%" height="100%" p="1rem" direction="column">
      <Flex width="100%" justifyContent="center" pb="1rem" direction="row">
        <Heading flex="1">Profile</Heading>
        <CloseButton as={Link} to={rootUrl()} />
      </Flex>
      <VStack flex="1" spacing="1rem" maxWidth="800px">
        <FormControl id="name">
          <FormLabel>Your name</FormLabel>
          <Flex direction="row">
            <Input type="text" value={name} onChange={e => setName(e.target.value)} />
            {name !== profileStore.profile.name && (
              <>
                <Button onClick={() => handleSave('name')} mx="1rem">
                  Save
                </Button>
                <Button onClick={() => setName(profileStore.profile.name)} variant="ghost" mr="1rem">
                  Cancel
                </Button>
              </>
            )}
          </Flex>
        </FormControl>
        <FormControl id="email">
          <FormLabel>Your Email address</FormLabel>
          <Flex direction="row">
            <Input type="email" value={email} onChange={e => setEmail(e.target.value)} />
            {email !== profileStore.profile.email && (
              <>
                <Button onClick={() => handleSave('email')} mx="1rem">
                  Save
                </Button>
                <Button onClick={() => setEmail(profileStore.profile.email)} variant="ghost" mr="1rem">
                  Cancel
                </Button>
              </>
            )}
          </Flex>
          <FormHelperText>We will never share your email.</FormHelperText>
        </FormControl>
        <FormControl id="nick">
          <FormLabel>Your Nick Name</FormLabel>
          <Flex direction="row">
            <Input type="text" value={nick} onChange={e => setNick(e.target.value)} />
            {nick !== userStore.myNick && (
              <>
                <Button onClick={() => handleSave('nick')} mx="1rem">
                  Save
                </Button>
                <Button onClick={() => setNick(userStore.myNick)} variant="ghost" mr="1rem">
                  Cancel
                </Button>
              </>
            )}
          </Flex>
          <FormHelperText>Can be 3-10 characters long?</FormHelperText>
        </FormControl>
        <FormControl as="fieldset">
          <FormLabel as="legend">UI Theme</FormLabel>
          <RadioGroup onChange={value => profileStore.setTheme(value as Theme)} value={profileStore.settings.theme}>
            <HStack spacing="24px">
              <Radio value="default">Old client</Radio>
              <Radio value="default-v2">Light</Radio>
              <Radio value="dark-v2">Dark</Radio>
            </HStack>
          </RadioGroup>
        </FormControl>
      </VStack>
    </Flex>
  );
};

export default observer(Profile);