Skip to content
Merged
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
5 changes: 3 additions & 2 deletions frontend/src/api/mailApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,8 @@ export async function updateMail(mailId, {
subject,
body,
sentTo,
saveAsDraft = true
saveAsDraft = true,
files = []
}) {
const url = `${API_BASE}/mails/${mailId}`;
const token = localStorage.getItem("token");
Expand All @@ -256,7 +257,7 @@ export async function updateMail(mailId, {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({subject, body, sentTo, saveAsDraft})
body: JSON.stringify({subject, body, sentTo, saveAsDraft, files})
});

if (!res.ok) throw new Error(`updateMail failed: ${res.status}`);
Expand Down
67 changes: 46 additions & 21 deletions frontend/src/main_page/ComposeEmail/ComposeEmail.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* ── Base drawer with transitions & overflow hidden ── */
.compose-email {
position: fixed;
bottom: 2vh;
Expand All @@ -8,31 +9,69 @@
background: #fff;
border: 1px solid #dadce0;
border-radius: 8px 8px 0 0;
box-shadow: 0 1px 2px rgba(60,64,67,0.15),
0 2px 6px rgba(60,64,67,0.15);
box-shadow:
0 1px 2px rgba(60,64,67,0.15),
0 2px 6px rgba(60,64,67,0.15);
display: flex;
flex-direction: column;
font-family: 'Roboto', sans-serif;
z-index: 1000;
color: #202124; /* default text color */
color: #202124;
transition: all 0.2s ease;
overflow: hidden;
}

/* ── Minimized: only header shows ── */
.compose-email.minimized {
height: auto; /* shrink to header bar */
width: 250px; /* Gmail‑style small width */
max-width: 100%;
bottom: 0;
}
.compose-email.minimized .compose-body,
.compose-email.minimized .compose-footer {
display: none;
}

/* ── Maximized: inset overlay with gutters ── */
.compose-email.maximized {
top: 10vh !important;
bottom: 10vh !important;
left: 10vw !important;
right: 10vw !important;
width: auto !important;
height: auto !important;
max-width: none !important;
max-height: none !important;
max-width: 80vw !important;
max-height: 80vh !important;
border-radius: 8px !important;
}
overflow: hidden;

/* inherit whatever the root .compose-email is set to */
background: inherit !important;
border-color: inherit !important;
}

/* ── Responsive auto‑minimize under 600px ── */
@media (max-width: 600px) {
.compose-email {
left: 0 !important;
right: 0 !important;
width: 100% !important;
max-width: none;
}
/* collapse unless user manually maximized */
.compose-email:not(.maximized) {
height: auto;
bottom: 0;
}
/* if maximized, fill screen */
.compose-email.maximized {
height: 100% !important;
width: 100% !important;
}
}

/* --- existing styles below this line --- */

.compose-header {
background: #f1f3f4;
Expand All @@ -49,11 +88,10 @@
color: #202124;
}

/* --- Only this part was added for dark mode title --- */
/* Dark mode title override */
.compose-email.dark .compose-title {
color: #f1f3f4 !important;
}
/* ---------------------------------------- */

.compose-controls .control-btn {
background: transparent;
Expand Down Expand Up @@ -193,7 +231,6 @@
border-bottom-color: #1a73e8;
}


.attachment-item {
display: flex;
align-items: center;
Expand Down Expand Up @@ -232,18 +269,6 @@
color: #d93025;
}

/* Optional: dark mode tweaks */
.compose-email.dark .attachment-item {
color: #e8eaed;
}
.compose-email.dark .remove-btn {
color: #9aa0a6;
}
.compose-email.dark .remove-btn:hover {
color: #f28b82;
}


.compose-footer {
padding: 0.5em 1em;
display: flex;
Expand Down
10 changes: 9 additions & 1 deletion frontend/src/main_page/ComposeEmail/ComposeEmail.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export default function ComposeEmail({
editorRef.current.innerHTML = initial;
}

setAttachments(draftMail.attachments || []);
setAttachments(draftMail.files || []);
setToQuery('');
setSuggestions([]);
}, [draftMail]);
Expand All @@ -73,6 +73,14 @@ export default function ComposeEmail({
}, 300);
return () => clearTimeout(timer);
}, [toQuery]);
// ── auto‑minimize on narrow viewports ──
useEffect(() => {
const mql = window.matchMedia('(max-width: 600px)');
const handler = e => setView(e.matches ? 'minimized' : 'normal');
// modern API
mql.addEventListener('change', handler);
return () => mql.removeEventListener('change', handler);
}, []);

// Add recipient if not already present
const addRecipient = email => {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/main_page/MainPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ const MainPage = () => {

{composes.map(c => (
<ComposeEmail
key={c.id}
key={`${c.id}-${theme}`}
theme={theme}
offset={c.offset}
draftMail={c.draftMail}
Expand Down
6 changes: 3 additions & 3 deletions web_server/controllers/mails.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,12 +180,12 @@ const editDraft = async (req, res, userId, mail) => {
if (!mail.isDraft)
return res.status(400).json({error: 'error only drafts can be updated'});
// Get the input params and edit the mail
const {subject, body, sentTo = [], saveAsDraft = true} = req.body;
const {subject, body, sentTo = [], saveAsDraft = true, files = []} = req.body;
const sentToIds = convertMailsToIds(sentTo);

// just update the fields in this draft
if (saveAsDraft) {
const updated = Mails.updateDraft(mail.id, subject, body, sentToIds);
const updated = Mails.updateDraft(mail.id, subject, body, sentToIds, files);
return res.status(200).json(updated);
}
// turn the draft to a new mail
Expand All @@ -195,7 +195,7 @@ const editDraft = async (req, res, userId, mail) => {
return res.status(403).json({error: 'error mail contains blacklisted URLs'});
// delete the draft and send a new mail
Mails.deleteMail(userId, mail.id);
const ownerMail = Mails.sendNewMail(userId, subject, body, sentToIds);
const ownerMail = Mails.sendNewMail(userId, subject, body, sentToIds, files);
return res.status(201).location(`/mails/${ownerMail.id}`).json(ownerMail);
}

Expand Down