Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/techx/pigeon into unread_em…
Browse files Browse the repository at this point in the history
…ails
  • Loading branch information
sabpdo committed May 4, 2024
2 parents 3d78682 + 785adff commit 969b726
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 6 deletions.
10 changes: 10 additions & 0 deletions client/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 client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@tiptap/pm": "^2.1.12",
"@tiptap/react": "^2.1.12",
"@tiptap/starter-kit": "^2.1.12",
"@types/react-icons": "^3.0.0",
"node-fetch": "^3.3.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand Down
95 changes: 91 additions & 4 deletions client/src/routes/inbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
IconFolderOff,
IconCheck,
IconX,
IconTrash,
} from "@tabler/icons-react";

interface Thread {
Expand Down Expand Up @@ -86,6 +87,10 @@ export default function InboxPage() {

const [response, setResponse] = useState<Response | undefined>(undefined);

const [storedResponses, setStoredResponses] = useState<{
[key: number]: Response;
}>({});

const viewport = useRef<HTMLDivElement>(null);

const editor = useEditor(
Expand Down Expand Up @@ -176,11 +181,20 @@ export default function InboxPage() {
};

const getResponse = () => {
// Checks if response is already stored
const currEmailID =
activeThread.emailList[activeThread.emailList.length - 1].id;
if (storedResponses[currEmailID]) {
const oldResponse = storedResponses[currEmailID];
setResponse(oldResponse);
setContent(oldResponse.content.replace("\n", "<br/>"));
return;
}

// Otherwise fetches response from server
const formData = new FormData();
formData.append(
"id",
activeThread.emailList[activeThread.emailList.length - 1].id.toString(),
);
formData.append("id", currEmailID.toString());

fetch(`/api/emails/get_response`, {
method: "POST",
body: formData,
Expand All @@ -194,6 +208,9 @@ export default function InboxPage() {
});
})
.then((data) => {
setStoredResponses((oldResponses) => {
return { ...oldResponses, [currEmailID]: data };
});
setResponse(data);
setContent(data.content.replaceAll("\n", "<br/>"));
});
Expand Down Expand Up @@ -391,6 +408,66 @@ export default function InboxPage() {
});
};

const deleteThread = () => {
notifications.show({
id: "loading",
title: "Loading",
color: "red",
message: "Deleting thread...",
loading: true,
autoClose: false,
});
const formData = new FormData();
formData.append("id", active.toString());
fetch("/api/emails/delete", {
method: "POST",
body: formData,
})
.then((res) => {
if (res.ok) return res.json();
notifications.update({
id: "loading",
title: "Error!",
color: "red",
loading: false,
message: "Something went wrong!",
});
})
.then(() => {
setThreads((oldThreads) => {
const updatedThreads = oldThreads.filter(
(thread) => thread.id !== active,
);

let newActive = -1;

//setting to next email hopefully
if (updatedThreads.length > 0) {
const currentIndex = oldThreads.findIndex(
(thread) => thread.id === active,
);
if (currentIndex >= 0 && currentIndex < updatedThreads.length) {
newActive = updatedThreads[currentIndex].id;
} else if (currentIndex >= updatedThreads.length) {
newActive = updatedThreads[updatedThreads.length - 1].id;
}
}
setActive(newActive);
return updatedThreads;
});
notifications.update({
id: "loading",
title: "Success!",
color: "green",
message: "Deleted thread",
icon: <IconCheck />,
autoClose: 2000,
withCloseButton: false,
loading: false,
});
});
};

useEffect(() => {
if (activeThread && activeThread.emailList.length > threadSize) {
if (viewport && viewport.current)
Expand Down Expand Up @@ -752,6 +829,16 @@ export default function InboxPage() {
Unresolve
</Button>
)}

{!activeThread.resolved && (
<Button
leftSection={<IconTrash />}
color="red"
onClick={() => deleteThread()}
>
Delete
</Button>
)}
</Group>
</Stack>
</Box>
Expand Down
23 changes: 22 additions & 1 deletion server/controllers/emails.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,8 +371,11 @@ def send_email():
).scalar()
if not thread:
return {"message": "Thread not found"}, 400

# replace <br /> with \n in body
breaked_line_text = data["body"].replace("<br/>", "\n")
clean_regex = re.compile("<.*?>")
clean_text = re.sub(clean_regex, " ", data["body"])
clean_text = re.sub(clean_regex, " ", breaked_line_text)
context = {"body": data["body"]}
template = env.get_template("template.html")
body = template.render(**context)
Expand Down Expand Up @@ -519,6 +522,24 @@ def unresolve():
return {"message": "Successfully updated"}, 200


@emails.route("/delete", methods=["POST"])
def delete():
"""POST /delete
Delete an email thread.
"""
data = request.form
thread = db.session.execute(select(Thread).where(Thread.id == data["id"])).scalar()
if not thread:
return {"message": "Thread not found"}, 400
db.session.delete(thread)
db.session.commit()

print("deleted thread", flush=True)

return {"message": "Successfully deleted"}, 200


@emails.route("/get_threads", methods=["GET"])
def get_threads():
"""GET /get_threads
Expand Down
8 changes: 7 additions & 1 deletion server/models/email.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,13 @@ class Email(db.Model):
message_id: Mapped[str] = mapped_column(nullable=False)

response: Mapped[Optional["Response"]] = relationship(
"Response", back_populates="email", init=False
"Response",
back_populates="email",
cascade="all, delete-orphan",
single_parent=True,
uselist=False,
passive_deletes=True,
init=False,
)

is_reply: Mapped[bool] = mapped_column(nullable=False)
Expand Down

0 comments on commit 969b726

Please sign in to comment.