Skip to content

Commit

Permalink
Migrated to TypeSctipt
Browse files Browse the repository at this point in the history
  • Loading branch information
IhorKaren committed Oct 18, 2023
1 parent cc50146 commit 34aeea3
Show file tree
Hide file tree
Showing 31 changed files with 209 additions and 106 deletions.
1 change: 1 addition & 0 deletions debug.log
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[1018/210120.404:ERROR:check.cc(298)] Check failed: false. NOTREACHED log messages are omitted in official builds. Sorry!
15 changes: 8 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"@mui/icons-material": "^5.11.16",
"@mui/joy": "^5.0.0-alpha.82",
"@mui/material": "^5.13.3",
"@mui/types": "^7.2.6",
"@reduxjs/toolkit": "^1.9.5",
"@testing-library/jest-dom": "^5.16.3",
"@testing-library/react": "^12.1.4",
Expand Down
2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>Phonebook</title>

<!-- Start Single Page Apps for GitHub Pages -->
<script type="text/javascript">
Expand Down
5 changes: 5 additions & 0 deletions src/@types/custom.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ declare module '*.svg' {
export default content;
}

declare module '*.jpg' {
const content: any;
export default content;
}

declare module '*.png' {
const content: any;
export default content;
Expand Down
52 changes: 31 additions & 21 deletions src/Pages/Home/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState, ChangeEvent } from 'react';
import { useEffect, MouseEvent, useState, ChangeEvent } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import Box from '@mui/joy/Box';
import Typography from '@mui/joy/Typography';
Expand All @@ -9,7 +9,7 @@ import {
import { filter, getFilter } from 'Redux/Filter/filterSlice';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { Contact } from 'components/App.types';
import { Contact, NewContact } from 'components/App.types';
//
import Sidebar from 'components/SideBar/SideBar';
import Header from 'components/Header/Header';
Expand All @@ -18,14 +18,21 @@ import FilterForm from 'components/Filter/Filter';
import PhonebookForm from 'components/PhonebookForm/PhonebookForm';
import Contacts from 'components/Contacts/Contacts';

export enum Filter {
dateLast = 'dateLast',
dateFirst = 'dateFirst',
byName = 'byName',
byNameReverse = 'byNameReverse',
}

const Home = () => {
const { data = [], refetch } = useGetContactsQuery();
const [addContact, result] = useAddContactMutation();

const [sortedData, setSortedData] = useState<Contact[]>([]);
const [selectedSortBy, setSelectedSortBy] = useState('dateFromLast');
const [selectedSortBy, setSelectedSortBy] = useState<Filter>(Filter.dateLast);

const contactsFilter = useSelector(getFilter);
const contactsFilter: string = useSelector(getFilter);
const dispatch = useDispatch();

useEffect(() => {
Expand All @@ -34,27 +41,27 @@ const Home = () => {

useEffect(() => {
setSortedData([...data]);
setSelectedSortBy('dateFromLast');
setSelectedSortBy(Filter.dateLast);
}, [data]);

const addContacts = (name: string, number: string) => {
const checkName = data.some(
const checkName: boolean = data.some(
el => el.name.toLowerCase() === name.toLowerCase()
);

if (checkName) {
return toast.error(`${name} is already in contacts.`);
}

const newContact = {
name: name,
number: number,
const newContact: NewContact = {
name,
number,
};

addContact(newContact);
};

const getFilteredContacts = () => {
const getFilteredContacts = (): Contact[] => {
return sortedData.filter(contact =>
contact.name.toLowerCase().includes(contactsFilter.toLowerCase())
);
Expand All @@ -64,35 +71,38 @@ const Home = () => {
dispatch(filter(e.target.value));
};

const handleSortByChange = (newValue: string) => {
const handleSortByChange = (
e: MouseEvent<HTMLSelectElement>,
newValue: string
) => {
let newData: Contact[];

switch (newValue) {
case 'dateFromFirst':
setSelectedSortBy('dateFromFirst');
case Filter.dateFirst:
setSelectedSortBy(Filter.dateFirst);
newData = [...data].reverse();
break;

case 'byName':
case Filter.byName:
newData = [...data].sort((a, b) => a.name.localeCompare(b.name));
setSelectedSortBy('byName');
setSelectedSortBy(Filter.byName);
break;

case 'byNameReverse':
case Filter.byNameReverse:
newData = [...data].sort((a, b) => b.name.localeCompare(a.name));
setSelectedSortBy('byNameReverse');
setSelectedSortBy(Filter.byNameReverse);
break;

default:
setSelectedSortBy('dateFromLast');
setSelectedSortBy(Filter.dateLast);
newData = data;
break;
}

setSortedData([...newData]);
};

const filteredContacts = getFilteredContacts();
const filteredContacts: Contact[] = getFilteredContacts();

return (
<>
Expand All @@ -111,7 +121,7 @@ const Home = () => {
isLoading={result.isLoading}
/>
<FilterForm
onChange={handleFilterChange}
onFilterChange={handleFilterChange}
selectedValue={selectedSortBy}
selectChange={handleSortByChange}
/>
Expand All @@ -120,7 +130,7 @@ const Home = () => {
{data.length === 0 ? (
<p>You don't have contacts yet</p>
) : (
<Contacts options={filteredContacts} />
<Contacts array={filteredContacts} />
)}
</Main>
</Box>
Expand Down
4 changes: 2 additions & 2 deletions src/Pages/Login/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ const schema = Yup.object().shape({

const LoginForm = () => {
const dispatch = useDispatch<AppDispatch>();
const loginError = useSelector(authError);
const loading = useSelector(isLoading);
const loginError: boolean = useSelector(authError);
const loading: boolean = useSelector(isLoading);

useEffect(() => {
if (loginError) {
Expand Down
8 changes: 5 additions & 3 deletions src/Redux/Contacts/contactsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
import { RootState } from 'Redux/store';
import { Contact } from 'components/App.types';

import { NewContact } from 'components/App.types';

export const contactsApi = createApi({
reducerPath: 'contactsApi',
baseQuery: fetchBaseQuery({
baseUrl: 'https://connections-api.herokuapp.com/',
prepareHeaders: (headers, { getState }) => {
const token = (getState() as RootState).auth.token
const token = (getState() as RootState).auth.token;

// If we have a token set in state, let's assume that we should be passing it.
if (token) {
Expand All @@ -23,15 +25,15 @@ export const contactsApi = createApi({
query: () => `contacts`,
providesTags: ['Contact'],
}),
addContact: builder.mutation({
addContact: builder.mutation<Contact[], NewContact>({
query: data => ({
url: `contacts`,
method: 'POST',
body: data,
}),
invalidatesTags: ['Contact'],
}),
deleteContact: builder.mutation({
deleteContact: builder.mutation<Contact[], string>({
query: id => ({
url: `contacts/${id}`,
method: 'DELETE',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import * as React from 'react';
import { useColorScheme } from '@mui/joy/styles';
import DarkModeIcon from '@mui/icons-material/DarkMode';
import LightModeIcon from '@mui/icons-material/LightMode';
import IconButton from '@mui/joy/IconButton';
import IconButton, { IconButtonProps } from '@mui/joy/IconButton';

export default function ColorSchemeToggle({ onClick, sx, ...props }) {
export default function ColorSchemeToggle({
onClick,
sx,
...props
}: IconButtonProps) {
const { mode, setMode } = useColorScheme();
const [mounted, setMounted] = React.useState(false);
React.useEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const RegisterForm = lazy(() => import('../Pages/Register/Register'));
export function App() {
const dispatch = useDispatch<AppDispatch>();

const isRefreshing = useSelector(isRefresh);
const isRefreshing: boolean = useSelector(isRefresh);

useEffect(() => {
dispatch(refreshUser());
Expand Down
2 changes: 2 additions & 0 deletions src/components/App.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ export type Contact = {
name: string;
number: string;
};

export type NewContact = Omit<Contact, 'id'>;
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { FC } from 'react';
import ContactItem from 'components/ContactsItem/ContactsItem';
import { StyledList } from 'components/Contacts/Contacts.styled';
import { Contact } from 'components/App.types';

const Contacts = ({ options }) => {
type ContactsProps = {
array: Contact[];
};

const Contacts: FC<ContactsProps> = ({ array }) => {
return (
<>
<StyledList>
{options.map(el => {
{array.map(el => {
return <ContactItem key={el.id} el={el} />;
})}
</StyledList>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import { FC } from 'react';
import { useDeleteContactMutation } from 'Redux/Contacts/contactsApi';
import Box from '@mui/joy/Box';
import Avatar from '@mui/joy/Avatar';
import ListItem from '@mui/joy/ListItem';
import Typography from '@mui/joy/Typography';
import Button from '@mui/joy/Button';
import Underline from './Underline';
import { Contact } from 'components/App.types';

const ContactsItem = ({ el }) => {
type ContactsItemProps = {
el: Contact;
};

const ContactsItem: FC<ContactsItemProps> = ({ el }) => {
const [deleteContact, result] = useDeleteContactMutation();
const firstLetter = [...el.name];
const firstLetter = el.name[0];

return (
<ListItem sx={{ maxWidth: '500px' }}>
<Avatar>{firstLetter[0]}</Avatar>
<Avatar>{firstLetter}</Avatar>
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
<Typography component="p" sx={{ ml: '8px' }}>
{el.name}
Expand Down
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 34aeea3

Please sign in to comment.