Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 6 additions & 111 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,123 +1,18 @@
import { useState } from 'react'

import initialEmails from './data/emails'

import Header from './Header'
import EmailPage from './EmailPage'
import './styles/App.css'

const getReadEmails = emails => emails.filter(email => !email.read)

const getStarredEmails = emails => emails.filter(email => email.starred)

function App() {
const [emails, setEmails] = useState(initialEmails)
const [hideRead, setHideRead] = useState(false)
const [currentTab, setCurrentTab] = useState('inbox')

const unreadEmails = emails.filter(email => !email.read)
const starredEmails = emails.filter(email => email.starred)

const toggleStar = targetEmail => {
const updatedEmails = emails =>
emails.map(email =>
email.id === targetEmail.id
? { ...email, starred: !email.starred }
: email
)
setEmails(updatedEmails)
}

const toggleRead = targetEmail => {
const updatedEmails = emails =>
emails.map(email =>
email.id === targetEmail.id ? { ...email, read: !email.read } : email
)
setEmails(updatedEmails)
}

let filteredEmails = emails

if (hideRead) filteredEmails = getReadEmails(filteredEmails)

if (currentTab === 'starred')
filteredEmails = getStarredEmails(filteredEmails)
const [searchTerm, setSearchTerm] = useState('')

return (
<div className="app">
<header className="header">
<div className="left-menu">
<svg className="menu-icon" focusable="false" viewBox="0 0 24 24">
<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"></path>
</svg>

<img
src="https://ssl.gstatic.com/ui/v1/icons/mail/rfr/logo_gmail_lockup_default_1x_r2.png"
alt="gmail logo"
/>
</div>

<div className="search">
<input className="search-bar" placeholder="Search mail" />
</div>
</header>
<nav className="left-menu">
<ul className="inbox-list">
<li
className={`item ${currentTab === 'inbox' ? 'active' : ''}`}
onClick={() => setCurrentTab('inbox')}
>
<span className="label">Inbox</span>
<span className="count">{unreadEmails.length}</span>
</li>
<li
className={`item ${currentTab === 'starred' ? 'active' : ''}`}
onClick={() => setCurrentTab('starred')}
>
<span className="label">Starred</span>
<span className="count">{starredEmails.length}</span>
</li>

<li className="item toggle">
<label htmlFor="hide-read">Hide read</label>
<input
id="hide-read"
type="checkbox"
checked={hideRead}
onChange={e => setHideRead(e.target.checked)}
/>
</li>
</ul>
</nav>
<main className="emails">
<ul>
{filteredEmails.map((email, index) => (
<li
key={index}
className={`email ${email.read ? 'read' : 'unread'}`}
>
<div className="select">
<input
className="select-checkbox"
type="checkbox"
checked={email.read}
onChange={() => toggleRead(email)}
/>
</div>
<div className="star">
<input
className="star-checkbox"
type="checkbox"
checked={email.starred}
onChange={() => toggleStar(email)}
/>
</div>
<div className="sender">{email.sender}</div>
<div className="title">{email.title}</div>
</li>
))}
</ul>
</main>
<Header searchTerm={searchTerm} setSearchTerm={setSearchTerm} />
<EmailPage searchTerm={searchTerm} />
</div>
)
}


export default App
26 changes: 26 additions & 0 deletions src/EmailItem.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
function EmailItem({ email, toggleRead, toggleStar }) {
return (
<li className={`email ${email.read ? 'read' : 'unread'}`}>
<div className="select">
<input
className="select-checkbox"
type="checkbox"
checked={email.read}
onChange={() => toggleRead(email)}
/>
</div>
<div className="star">
<input
className="star-checkbox"
type="checkbox"
checked={email.starred}
onChange={() => toggleStar(email)}
/>
</div>
<div className="sender">{email.sender}</div>
<div className="title">{email.title}</div>
</li>
)
}

export default EmailItem
81 changes: 81 additions & 0 deletions src/EmailPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { useState } from 'react'
import initialEmails from './data/emails'
import Sidebar from './Sidebar'
import EmailItem from './EmailItem'

const getUnreadEmails = emails => emails.filter(email => !email.read)
const getStarredEmails = emails => emails.filter(email => email.starred)

function EmailPage({searchTerm}) {
const [emails, setEmails] = useState(initialEmails)
const [hideRead, setHideRead] = useState(false)
const [currentTab, setCurrentTab] = useState('inbox')

const unreadEmails = getUnreadEmails(emails)
const starredEmails = getStarredEmails(emails)

const toggleStar = targetEmail => {
setEmails(prevEmails =>
prevEmails.map(email =>
email.id === targetEmail.id
? { ...email, starred: !email.starred }
: email
)
)
}

const toggleRead = targetEmail => {
setEmails(prevEmails =>
prevEmails.map(email =>
email.id === targetEmail.id
? { ...email, read: !email.read }
: email
)
)
}

// Filtering logic
let filteredEmails = emails
if (hideRead) {
filteredEmails = getUnreadEmails(filteredEmails)
}
if (currentTab === 'starred') {
filteredEmails = getStarredEmails(filteredEmails)
}
if (searchTerm) {
const searchTermLowerCase = searchTerm.toLowerCase()
filteredEmails = filteredEmails.filter(
email =>
email.title.toLowerCase().includes(searchTermLowerCase) ||
email.sender.toLowerCase().includes(searchTermLowerCase)
)
}

return (
<>
<Sidebar
currentTab={currentTab}
setCurrentTab={setCurrentTab}
unreadEmails={unreadEmails}
starredEmails={starredEmails}
hideRead={hideRead}
setHideRead={setHideRead}
/>

<main className="emails">
<ul>
{filteredEmails.map(email => (
<EmailItem
key={email.id}
email={email}
toggleRead={toggleRead}
toggleStar={toggleStar}
/>
))}
</ul>
</main>
</>
)
}

export default EmailPage
26 changes: 26 additions & 0 deletions src/Header.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
function Header({ searchTerm, setSearchTerm }) {
return (
<header className="header">
<div className="left-menu">
<svg className="menu-icon" focusable="false" viewBox="0 0 24 24">
<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"></path>
</svg>
<img
src="https://ssl.gstatic.com/ui/v1/icons/mail/rfr/logo_gmail_lockup_default_1x_r2.png"
alt="gmail logo"
/>
</div>

<div className="search">
<input
className="search-bar"
placeholder="Search mail"
value={searchTerm}
onChange={e => setSearchTerm(e.target.value)}
/>
</div>
</header>
)
}

export default Header
34 changes: 34 additions & 0 deletions src/Sidebar.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
function Sidebar({ currentTab, unreadEmails, starredEmails, hideRead, setHideRead }){
return (
<nav className="left-menu">
<ul className="inbox-list">
<li
className={`item ${currentTab === 'inbox' ? 'active' : ''}`}
onClick={() => setCurrentTab('inbox')}
>
<span className="label">Inbox</span>
<span className="count">{unreadEmails.length}</span>
</li>
<li
className={`item ${currentTab === 'starred' ? 'active' : ''}`}
onClick={() => setCurrentTab('starred')}
>
<span className="label">Starred</span>
<span className="count">{starredEmails.length}</span>
</li>

<li className="item toggle">
<label htmlFor="hide-read">Hide read</label>
<input
id="hide-read"
type="checkbox"
checked={hideRead}
onChange={e => setHideRead(e.target.checked)}
/>
</li>
</ul>
</nav>
)
}

export default Sidebar
2 changes: 1 addition & 1 deletion src/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
)