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
4 changes: 3 additions & 1 deletion frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import UploadJson from "./pages/UploadJson";
import SuburbLivability from "./pages/SuburbLivability";
import ForBusinesses from "./pages/ForBusinesses";
import ForIndividuals from "./pages/ForIndividuals";
import CompareSuburbs from "./pages/CompareSuburbs";
import "./App.css";

const AppContent = () => {
const location = useLocation();
const knownPaths = ["/uploadjson", "/businesses", "/individuals"];
const knownPaths = ["/uploadjson", "/businesses", "/individuals", "/compare"];

const hideNavBarPaths = ["/"];

Expand All @@ -33,6 +34,7 @@ const AppContent = () => {
<Route path="/uploadjson" element={<UploadJson />} />
<Route path="/businesses" element={<ForBusinesses />} />
<Route path="/individuals" element={<ForIndividuals />} />
<Route path="/compare" element={<CompareSuburbs />} />
</Routes>
</div>
);
Expand Down
9 changes: 8 additions & 1 deletion frontend/src/components/Navbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,14 @@ const Navbar = () => {
>
For Individuals
</motion.button>

<motion.button
whileHover={{ y: -4 }}
transition={{ type: "spring", stiffness: 300 }}
className={`nav-btn ${isActive('/compare') ? 'active' : ''}`}
onClick={() => navigate('/compare')}
>
Compare Suburbs
</motion.button>
</div>
</div>
)
Expand Down
84 changes: 84 additions & 0 deletions frontend/src/components/Panel3.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@


const mockData = [
{
name: 'Hornsby',
investmentScore: 82,
commercialScore: 74,
medianPrice: '$780,000',
crimeRate: 'Low (3.2/10)',
affordabilityIndex: '6.5',
livabilityScore: 88,
},
{
name: 'Bondi',
investmentScore: 76,
commercialScore: 81,
medianPrice: '$720,000',
crimeRate: 'Moderate (5.1/10)',
affordabilityIndex: '7.2',
livabilityScore: 80,
},
{
name: 'Artarmon',
investmentScore: 89,
commercialScore: 68,
medianPrice: '$850,000',
crimeRate: 'Low (2.7/10)',
affordabilityIndex: '5.8',
livabilityScore: 91,
},
];

const metrics = [
{ key: 'investmentScore', label: 'Investment Score' },
{ key: 'commercialScore', label: 'Commercial Score' },
{ key: 'medianPrice', label: 'Suburb Median Prices' },
{ key: 'crimeRate', label: 'Weighted Crime Rate' },
{ key: 'affordabilityIndex', label: 'Property Affordability Index' },
{ key: 'livabilityScore', label: 'Suburb Livability Score' },
];

import { ChevronDown } from "lucide-react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { ReactNode, useState } from "react";
import RunButton from "./Buttons"
import { motion } from "framer-motion";

export default function SuburbPanel({ title, description, subDescriptionLabel, subDescriptionItems = [], children, runbutton, loading}) {
const [isOpen, setIsOpen] = useState(false);

const myAnimation = {
initial: { opacity: 0, x: -50 },
inView: { opacity: 1, x: 0 },
hover: { borderColor: "rgba(255,255,255,1)", scale: 1.02 , y: -6}
};
return (
<motion.div
whileInView='inView'
whileHover='hover'
viewport={{ once: true }}
variants={myAnimation}
className={`flex w-[90vw] pt-8 mx-auto flex-col rounded-xl border border-white/30 bg-[linear-gradient(to_top_right,rgba(24,44,88,0.4)_13.2%,rgba(227,228,252,0.02)_100%)] px-7 text-white backdrop-blur-20 ${loading && "animate-bg"}`}>

<div className="flex flex-col items-center text-center px-6">
<h2 className="text-[32px] text-white font-bold text-center">{title}</h2>
</div>

<div
style={{
maxHeight: "10000px",
opacity: "1",
transition: "max-height 400ms ease-in-out, opacity 400ms ease-in-out",
}}
className="flex flex-col gap-4 items-center py-5"
>
<div className="w-full flex flex-col gap-6 items-center px-15 pt-8">
{children}
</div>
<div>{runbutton}</div>
</div>
</motion.div>
);
}
148 changes: 148 additions & 0 deletions frontend/src/pages/Compare.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { useState } from "react";
import axios from "axios";
import RunButton from "../components/Buttons";
import BasicInput from "../components/Inputs";
import Panel from "@/components/Blocks";
import Loading from "@/components/Loading";
import { Button } from "@/components/ui/button";
import SuburbPanel from "@/components/Panel3";
import { ArrowUpRight, Shield, Home, DollarSign, BarChart2, Smile } from "lucide-react";


// Compare Suburbs Panels
const metrics = [
{ key: 'medianPrice', label: 'Average Property Price' },
{ key: 'crimeRate', label: 'Weighted Crime Rate' },
{ key: 'investmentScore', label: 'Investment Potential Score' },
{ key: 'commercialScore', label: 'Commercial Score' },
{ key: 'affordabilityIndex', label: 'Property Affordability Index' },
{ key: 'livabilityScore', label: 'Suburb Livability Score' }
];

const metricIcons = {
investmentScore: <ArrowUpRight className="w-20 h-20 text-green-400" />,
commercialScore: <Home className="w-30 h-30 text-blue-400" />,
crimeRate: <Shield className="w-20 h-20 text-white" />,
affordabilityIndex: <BarChart2 className="w-20 h-20 text-purple-400" />,
livabilityScore: <Smile className="w-20 h-20 text-white" />
};

const results = [
{
name: 'Hornsby',
investmentScore: 73.94,
commercialScore: 74.23,
medianPrice: '$780,000',
crimeRate: '4.29',
affordabilityIndex: '6.14',
livabilityScore: 68.32,
},
{
name: 'Bondi',
investmentScore: 76,
commercialScore: 81,
medianPrice: '$720,000',
crimeRate: '23.72',
affordabilityIndex: '4.21',
livabilityScore: 53.18,
},
{
name: 'Artarmon',
investmentScore: 89,
commercialScore: 68,
medianPrice: '$850,000',
crimeRate: '6.66',
affordabilityIndex: '9.52',
livabilityScore: 66.85,
}
];

const Compare = () => {
const [id, setId] = useState(null);
const [compare, setCompare] = useState(null)
const [suburb1, setSuburb1] = useState("");
const [suburb2, setSuburb2] = useState("");
const [suburb3, setSuburb3] = useState("");
const [loading, setLoading] = useState(false);

const fetchData = async () => {
if (!suburb1 || !suburb2 || !suburb3) {
alert("missing suburb");
return;
}
// const requestBody = {
// id: id,
// function_name: "investment_potential",
// top_n: topN
// };
setLoading(true);
// const response = await axios.post(
// "https://7c4yt1yrr2.execute-api.us-east-1.amazonaws.com/investment_potential",
// requestBody,
// {
// headers: {
// "Content-Type": "application/json",
// },
// }
// );
// console.log("response = ", response.data.investment_potentials);
//setCompare(response.data.investment_potentials);
setCompare(results)
setLoading(false)
}

return (
<div>
<SuburbPanel title="Select suburbs to compare">
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 w-full">
<BasicInput
type="text"
name="suburb1"
placeholder="Suburb"
onChange={(e) => setSuburb1(e.target.value)}
/>
<BasicInput
type="text"
name="suburb2"
placeholder="Suburb"
onChange={(e) => setSuburb2(e.target.value)}
/>
<BasicInput
type="text"
name="suburb3"
placeholder="Suburb"
onChange={(e) => setSuburb3(e.target.value)}
/>
</div>

{loading ? (
<Loading />
) : (
<RunButton text={"Submit"} onClick={fetchData} />
)}
{compare && !loading && (
<div>
<div className="grid grid-cols-3 gap-30 overflow-visible">
{results.map((suburb, i) => (
<div key={i} className="text-white text-center pl-4">
<p className="sticky top-10 bg-[linear-gradient(to_top_right,rgba(24,44,88,0.4)_13.2%,rgba(227,228,252,0.02)_100%)] text-4xl font-bold py-10 z-10 my-20 rounded-2xl">
{suburb.name}
</p>
{metrics.map((metric) => (
<div key={metric.key} className="mb-6">
<div className="flex justify-center mb-5">{metricIcons[metric.key]}</div>
<p className="text-7xl font-semibold mb-2">{suburb[metric.key]}</p>
<p className="text-3xl mb-30">{metric.label}</p>
</div>
))}
</div>
))}
</div>
</div>
)}
</SuburbPanel>
</div>
);
};

export default Compare;
44 changes: 44 additions & 0 deletions frontend/src/pages/CompareSuburbs.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {motion} from "framer-motion";
import { useEffect, useState } from "react";
import axios from "axios";
import RunButton from "../components/Buttons";
import BasicInput from "../components/Inputs";
import Panel from "@/components/Blocks";
import Loading from "@/components/Loading";
import SimplePanel from "@/components/Panel3";
import SuburbPanel from "@/components/Panel3";
import Compare from "./Compare"

// Compare Suburbs Page

const CompareSuburbs = () => {
const maskVariants = {
hidden: { clipPath: "inset(0 0 100% 0)" },
show: {
clipPath: "inset(0 0 0% 0)",
transition: {
duration: 1.2,
ease: [0.25, 0.1, 0.25, 1],
},
},
};
return (
<>
<motion.div
variants={maskVariants}
initial="hidden"
animate="show"
className="animate-fade-blur-in relative w-full h-[60vh] bg-cover bg-[url(/darkbuildings.jpg)] bg-center backdrop-blur-sm bg-white/10">
<div className="absolute inset-0 bg-black/30 backdrop-blur-[1px] flex items-center justify-center">
<h1 className="animate-fade-move-blur-in text-white text-[80px] font-bold">Compare Suburbs</h1>
</div>
<div className="absolute bottom-0 w-full h-3 bg-gradient-to-t from-[#010314]/90 to-transparent backdrop-blur-md"></div>
</motion.div>
<div className="page w-full px-10 py-10 flex justify-center">
<Compare />
</div>
</>
)
}

export default CompareSuburbs;
1 change: 0 additions & 1 deletion frontend/src/pages/ForBusinesses.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ const ForBusinesses = () => {
<InvestmentPotential />
<CommercialRecommendations />
<CommercialRecommendationsTargeted />
<InfluenceFactor/>
</div>
</>
);
Expand Down