Giter Club home page Giter Club logo

rentex-ignite-react-native's Introduction

rentex-Ignite-React-Native

Projeto aluguel de carros, consumindo API local.

Tabelas de conteudos

Visão Geral

Desafio

  • Consumir api local de aluguel de carros.

Figma

Construção

  • React
  • Styled Component
  • Type Script
  • JSX

O que eu aprendi

Fortaleci meus conhecimentos no consumo de API,type script,React Native é animações

Toda aplicação, foco foi em composição usando o principio design de Software Atomics desing Atomics

Quando tem necessidade do componente ficar evidente independente do scroll,maneira simples e eficiente de realizar e colocar fora da scroll. Componente Content é scrollView,objetivo e manter botão de confirmar "período do aluguel" sempre evidente,então construi uma view em torno fora da scroll view,assim sempre fica evidente botão.

<Container>
  <Header>
    <BackButton onPress={handleGoBack} />
  </Header>
  <CardSliderImg>
    <CarSlider listImg={car.photos} />
  </CardSliderImg>
  <Content
    contentContainerStyle={{ paddingHorizontal: 24, alignItems: 'center' }}
    showsVerticalScrollIndicator={false}
  >
    <ViewCarDetails>
      <ViewDetails>
        <BrandText>{car.brand}</BrandText>
        <ModelText>{car.name}</ModelText>
      </ViewDetails>
      <ViewRente>
        <DayText>{car.rent.period}</DayText>
        <PriceText>R$ {car.rent.price}</PriceText>
      </ViewRente>
    </ViewCarDetails>
    <Accessories>
      {car.accessories.map((accessory) => (
        <Accessory
          name={accessory.name}
          key={accessory.type}
          icon={getIcons(accessory.type)}
        />
      ))}
    </Accessories>
    <AboutText>{car.about}</AboutText>
  </Content>
  <Footer>
    <Button
      description="Escolha período do aluguel"
      onPress={handleScheduling}
    />
  </Footer>
</Container>

Com !! determino que meu conteúdo vai ser um estado logico ou seja quando possuir conteúdo vai ser verdadeiro,quando não possuir vai ser falso. Interessante,porque assim evito criar novas constantes e reaproveito código

<TextDate isDate={!!rentalPeriod.startDayFormatted}>
  {rentalPeriod.startDayFormatted}
</TextDate>

Aprendi conceitos novos e melhorei consumo de Api. Primeiro conceito é atualizar o json com o pedido do cliente. Primeiro recebo todas as datas ja cadastradas, para evitar sobrescrever os dados anteriores isso foi feito em "schedulesByCar" e em unavailable_dates eu construo um novo array com tudo do anterior e coloco as novas data.
Referencia aqui e feito pel car.id
Para atualizar um json método usado e o put,primeiro eu paso o endereço que desejo atualizar apos isto passo o parâmetro. No meu caso parâmetro foi próprio car.id, dai atualizo o id que no casso foi o selecionado e coloco todas datas que foram registradas. Com método post crio um novo recurso. Para meu caso de uso,setei o id do usuário no async storage,assim consigo recuperar ao longo da aplicação,apos isto verifico se possui um id registrado no async storage, caso possua,assumo que possui carros alugados pelo usuário,ja que com método post eu crio um novo recurso no json com id do usuário, objeto do carro e também as datas selecionado. Dentro do if faço esse controle,caso não possua um id e feito um post com esses recursos , caso possua faco um put para atualizar o recurso Para realizar put,post,get precisa verifica na documentação se api possui esses recursos,neste caso usei o json_server para simular uma api local

     async function handleSchedulingComplete() {
    setIsLoading(true);
    const schedulesByCar = await api.get(`/schedules_bycars/${car.id}`);
    const unavailable_dates = [
      ...schedulesByCar.data.unavailable_dates,
      ...date,
    ];
    api
      .put(`/schedules_bycars/${car.id}`, {
        id: car.id,
        unavailable_dates,
      })
      .then(async () => {
        const getUserId = await AsyncStorage.getItem(userId);
        const parseUserId = getUserId ? JSON.parse(getUserId!) : '';
        const carUserId = uuidV4();
        const rentalsAllPeriod = {
          car,
          carUserId,
          startDate: format(addDays(new Date(date[0]), 1), 'dd/MM/yy'),
          endDate: format(
            addDays(new Date(date[date.length - 1]), 1),
            'dd/MM/yy',
          ),
        };

        if (parseUserId === '') {
          const idUser = uuidV4();
          AsyncStorage.setItem(userId, JSON.stringify(idUser));
          await api.post('/schedules_byuser', {
            carByUser: [rentalsAllPeriod],
            user_id: idUser,
            id: idUser,
          });
          navigation.navigate('SchedulingComplete');
        } else {
          const getCars = await api.get(`/schedules_byuser/${parseUserId}`);
          const allRentalUser = [...getCars.data.carByUser, rentalsAllPeriod];
          await api.put(`/schedules_byuser/${parseUserId}`, {
            carByUser: allRentalUser,
            user_id: parseUserId,
            id: parseUserId,
          });
          navigation.navigate('SchedulingComplete');
        }
      })
      .catch((error) => Alert.alert(error));
  }

Para usar json-server primeiro precisa indicar aonde esta a sua api em formato json,apos isto precisa passar os parâmetros opcionais no caso usei ip da minha maquina,para poder testar no celular físico, nao usei localhost, porque expo encontra meu celular pelo ip, passei o parâmetro da porta e por fim delay para atrasar api

  "api": "json-server ./src/utils/server.json --host 192.168.43.99 --port 3333 --delay 700"

Usei recurso interessante para realizar um slide dinâmico,ideia e conforme a lista renderiza novas imagens, reflete no canto superior uma barra de progresso,comum em alguns app que ao passar as imagens para lado,em cima uma bolinha fica escura. Para realizar foi usado useRef,porque com ele consigo acessar diretamente o componente e também foi usado uma função do flatList "onViewableItemsChanged" esta função passa retorna callback o 'info',esse info e a posição que a imagem esta na sua lista. Usando use ref e a tipagem consegui pegar a posição correta e passei para componente View Slider, nesse componente eu passo uma props que ao ser verdadeira deixa opacidade em 1, Repara que foi usado o [0],porque a ideia e pegar exatamente quando a imagem estar totalmente aparente

interface ViewSliderProps {
  viewableItems: ViewToken[];
  changed: ViewToken[];
}

export function CarSlider({ listImg }: CarSliderProps): JSX.Element {
  const [indexImg, setIndexImg] = useState(0);

  const handleVIew = useRef((info: ViewSliderProps) => {
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    const index = info.viewableItems[0].index!;
    setIndexImg(index);
  });
  return (
    <Fragment>
      <ViewSlider numberSelected={indexImg} listImg={listImg} />
      <FlatList
        data={listImg}
        keyExtractor={(key) => key}
        renderItem={({ item }) => (
          //as vezes colocar uma view em torno auxilia na estilização
          <ImgWrap>
            <CarImg source={{ uri: item }} resizeMode="contain" />
          </ImgWrap>
        )}
        horizontal={true}
        showsHorizontalScrollIndicator={false}
        contentContainerStyle={{
          paddingRight: 47,
        }}
        onViewableItemsChanged={handleVIew.current}
      />
    </Fragment>
  );
}

/*---------------------------*/
export function ViewSlider({
  listImg,
  numberSelected,
}: listImgProps): JSX.Element {
  return (
    <Container>
      {listImg.map((__, index) => (
        <ViewSelected
          key={String(index)}
          isSelect={numberSelected === index ? true : false}
        />
      ))}
    </Container>
  );
}

Usei e abusei de uma lib muita boa para calendários,calendars, em baixo esta um exemplo de uso,pegando a data exata que o usuário colocou e o intervalo escolhido,foi usado também date fns para gerar os intervalos. Algumas interfaces sao da propriá documentação como "MarkerDatesProps" que recebe um array de string; ideia dentro de [date] e pegar o conteúdo dentro e nao o array.

interface MarkerDatesProps {
  [date: string]: {
    textColor: string,
    color: string,
    disabled?: boolean,
    disabledTouchEvent?: boolean,
  };
}

interface DayProps {
  day: number;
  month: number;
  year: number;
  timestamp: number;
  dateString: string;
}

interface CalendarProps {
  markedDates: MarkerDatesProps;
  onDayPress: DateCallbackHandler;
}

function CustomCalendar({
  markedDates,
  onDayPress,
}: CalendarProps): JSX.Element {
  const { colors, fonts } = useTheme();
  return (
    <Container>
      <Calendar
        renderArrow={(direction) => (
          <Feather
            color={colors.text_detail}
            size={24}
            name={direction === 'left' ? 'chevron-left' : 'chevron-right'}
          />
        )}
        headerStyle={{
          borderBottomColor: colors.text_detail,
          borderBottomWidth: 0.5,
          paddingBottom: 10,
          marginBottom: 10,
        }}
        theme={{
          monthTextColor: colors.title,
          textMonthFontWeight: '600',
          textMonthFontFamily: fonts.archivo_600,
          textMonthFontSize: 20,
          dayTextColor: colors.title,
          textDayFontWeight: '400',
          textDayFontSize: 15,
          textDayFontFamily: fonts.inter_400,
        }}
        //dia 1 e para calendário iniciar em segunda,esta assim no design do figma
        firstDay={1}
        minDate={new Date()}
        markedDates={markedDates} //isto e um array correspondente ao marKingType
        markingType="period"
        onDayPress={onDayPress} //dia selecionado
      />
    </Container>
  );
}

export {
  DayProps,
  CalendarProps,
  CustomCalendar,
  MarkerDatesProps,
  getIntervalDays,
};
export function Scheduling(): JSX.Element {
  function handleSchedulingDetails() {
    //preciso passar chaves para objeto via parâmetro,
    //car:car, date" Objet.Key()
    navigation.navigate('SchedulingDetails', {
      car,
      date: Object.keys(markDate),
    });
  }

  function handleChangeDate(date: DayProps) {
    let start = !lastDateSelected.timestamp ? date : lastDateSelected;
    //aqui garanto que sempre vai haver uma unica data clicado no meu estado,
    //esta data sempre sera o inicio dela,porque se nao houver data meu estado vai ser date
    // se houver sera o próprio estado
    let end = date;
    if (start.timestamp > end.timestamp) {
      start = end;
      end = start;
    }
    setLastDateSelect(end);
    //função acima so estou tratando o primeiro dia clicado,sempre priorizando a data menor
    const interval = getIntervalDays(start, end);
    setMarkDate(interval);
    const startDay = Object.keys(interval)[0];
    const enDay = Object.keys(interval)[Object.keys(interval).length - 1]; //pegar todos objetos com chave final
    setRentalPeriod({
      startDayFormatted: format(addDays(new Date(startDay), 1), 'dd/MM/yy'),
      endDayFormatted: format(addDays(new Date(enDay), 1), 'dd/MM/yy'),
    });
  }

  return (
    <Content>
      <CustomCalendar
        markedDates={markDate}
        onDayPress={handleChangeDate}
        // função onDayPress  ja recebe um date ao clicar no calendário,então nao precisou
        //informar na função
      />
    </Content>
  );
}

Feature

  • Hooks
  • styled component
  • Atomics
  • Media Screen
  • Tipagem

Dependências

rentex-ignite-react-native's People

Contributors

kenjimaeda54 avatar

Stargazers

weber souza || dev-CMS avatar Luiz Gabriel avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.