Skip to content

Commit 17a75bc

Browse files
authored
Merge pull request #305 from hermannsalan/homepage
Homepage
2 parents 42ea68b + e59fd5b commit 17a75bc

22 files changed

Lines changed: 669 additions & 24 deletions

backend/tenantfirstaid/feedback.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,19 @@ def send_feedback() -> Tuple[str, int]:
3434
]
3535

3636
if not file:
37-
return "No file provided", 404
37+
name = request.form.get("name")
38+
subject = request.form.get("subject")
39+
email_params = {
40+
"subject": subject or "Homepage Feedback",
41+
"from_email": os.getenv("SENDER_EMAIL"),
42+
"to": [os.getenv("RECIPIENT_EMAIL")],
43+
"body": f"From: {name}\n\n{feedback}",
44+
}
45+
try:
46+
EmailMessage(**email_params).send()
47+
return "Message sent", 200
48+
except Exception as e:
49+
return f"Send failed: {str(e)}", 500
3850

3951
html_content: str = file.read().decode("utf-8")
4052
pdf_content: Optional[bytes] = convert_html_to_pdf(html_content)

frontend/package-lock.json

Lines changed: 10 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/src/App.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Navbar from "./shared/components/Navbar/Navbar";
44
import Chat from "./Chat";
55
import LoadingPage from "./pages/LoadingPage";
66
import PageLayout from "./layouts/PageLayout";
7+
import HomePage from "./pages/HomePage/HomePage";
78

89
// Lazy-loading for less frequented pages
910
const About = lazy(() => import("./About"));
@@ -17,12 +18,13 @@ export default function App() {
1718
<Navbar />
1819
<PageLayout>
1920
<Routes>
20-
<Route path="/" element={<Chat />} />
21+
<Route path="/" element={<HomePage />} />
2122
<Route
2223
path="/*"
2324
element={
2425
<Suspense fallback={<LoadingPage />}>
2526
<Routes>
27+
<Route path="/chat" element={<Chat />} />
2628
<Route path="/letter" element={<Letter />} />
2729
<Route path="/letter/:org/:loc?" element={<Letter />} />
2830
<Route path="/about" element={<About />} />
455 KB
Loading
640 KB
Loading
444 KB
Loading

frontend/src/layouts/PageLayout.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ interface Props {
77

88
export default function PageLayout({ children }: Props) {
99
const { pathname } = useLocation();
10-
const isChatPages = pathname === "/" || pathname.startsWith("/letter");
10+
const isChatOrHomePages =
11+
pathname === "/" ||
12+
pathname.startsWith("/letter") ||
13+
pathname.startsWith("/chat");
1114

1215
return (
1316
<div
1417
className={clsx(
1518
"flex justify-center pt-(--navbar-height)",
16-
isChatPages ? "h-dvh" : "items-center sm:pt-32 sm:pb-16",
19+
isChatOrHomePages ? "h-dvh" : "items-center sm:pt-32 sm:pb-16",
1720
)}
1821
id="page-layout"
1922
>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const brainyFeatures = [
2+
{
3+
title: "Ask questions",
4+
desc: "Chat with Brainy about your housing issues.",
5+
id: "chat",
6+
},
7+
{
8+
title: "Write letters",
9+
desc: "Brainy can help draft letters to your landlord.",
10+
id: "letter",
11+
},
12+
];
13+
14+
export default brainyFeatures;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//Headers for the comparison grid
2+
const headers = ["", "Tenant First Aid", "Traditional Legal Aid", "ChatGPT"];
3+
4+
// 2. Extract table data into a clean structure
5+
const comparisonData = [
6+
{
7+
feature: "Always available",
8+
tenantFirstAid: true,
9+
traditional: false,
10+
chatgpt: true,
11+
},
12+
{
13+
feature: "Always free",
14+
tenantFirstAid: true,
15+
traditional: false,
16+
chatgpt: false,
17+
},
18+
{
19+
feature: "No eligibility requirements",
20+
tenantFirstAid: true,
21+
traditional: false,
22+
chatgpt: true,
23+
},
24+
{
25+
feature: "Provides legal advice",
26+
tenantFirstAid: false,
27+
traditional: true,
28+
chatgpt: false,
29+
},
30+
{
31+
feature: "Only references relevant laws",
32+
tenantFirstAid: true,
33+
traditional: true,
34+
chatgpt: false,
35+
},
36+
{
37+
feature: "Direct advocacy with court/landlords",
38+
tenantFirstAid: false,
39+
traditional: true,
40+
chatgpt: false,
41+
},
42+
];
43+
44+
export { headers, comparisonData };
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import React from "react";
2+
import CheckCircle from "../../../shared/components/CheckCircleIcon";
3+
import XCircle from "../../../shared/components/XCircleIcon";
4+
import { headers, comparisonData } from "./ComparisonData";
5+
6+
export default function ComparisonGrid() {
7+
const renderIcon = (hasFeature: boolean) =>
8+
hasFeature ? <CheckCircle /> : <XCircle />;
9+
10+
return (
11+
<div className="bg-[#E6D5B8]/10 backdrop-blur-lg border border-[#E6D5B8]/20 p-12 shadow-[0_15px_40px_rgba(0,0,0,0.2)] rounded-3xl overflow-hidden max-[950px]:overflow-x-auto max-[950px]:p-6 max-[950px]:pl-0">
12+
<div className="grid grid-cols-4 gap-px bg-[#E6D5B8]/10 max-[950px]:min-w-[700px] [&>div:nth-child(4n+1)]:max-[950px]:sticky [&>div:nth-child(4n+1)]:max-[950px]:left-0 [&>div:nth-child(4n+1)]:max-[950px]:z-10 [&>div:nth-child(4n+1)]:max-[950px]:border-r [&>div:nth-child(4n+1)]:max-[950px]:border-[#E6D5B8]/20 [&>div:nth-child(4n+1)]:max-[950px]:bg-[#0E362D] [&>div:nth-child(1)]:max-[950px]:!bg-emerald-900">
13+
{/* Render Headers */}
14+
{headers.map((header) => (
15+
<div
16+
key={header == " " ? "empty-header" : header}
17+
className="p-5 font-bold bg-emerald-900/80 text-[#F4F4F2] text-center"
18+
>
19+
{header}
20+
</div>
21+
))}
22+
23+
{/* Render Data Rows */}
24+
{comparisonData.map((row) => (
25+
// React.Fragment is crucial here so we don't break CSS Grid and nth-child selectors
26+
<React.Fragment key={row.feature}>
27+
{/* Feature Name (Sticky Column) */}
28+
<div className="p-5 bg-[#E6D5B8]/5 text-[#F4F4F2] text-center flex items-center justify-center font-medium">
29+
{row.feature}
30+
</div>
31+
32+
{/* Tenant First Aid Column */}
33+
<div className="p-5 bg-[#E6D5B8]/5 text-center font-bold flex items-center justify-center">
34+
{renderIcon(row.tenantFirstAid)}
35+
</div>
36+
37+
{/* Traditional Legal Aid Column */}
38+
<div className="p-5 bg-[#E6D5B8]/5 text-[#F4F4F2] text-center flex items-center justify-center font-medium">
39+
{renderIcon(row.traditional)}
40+
</div>
41+
42+
{/* ChatGPT Column */}
43+
<div className="p-5 bg-[#E6D5B8]/5 text-[#F4F4F2] text-center flex items-center justify-center font-medium">
44+
{renderIcon(row.chatgpt)}
45+
</div>
46+
</React.Fragment>
47+
))}
48+
</div>
49+
</div>
50+
);
51+
}

0 commit comments

Comments
 (0)