Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add license plate lookup page #407

Open
wants to merge 23 commits into
base: production
Choose a base branch
from
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
11 changes: 10 additions & 1 deletion page-settings/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,21 @@ export const PAGES = [
img: { src: "/assets/strategic-direction.png", alt: "Strategic direction" },
external: true,
},

{
title: "Open Data",
description: "Browse and download the data that powers our operations",
href: "https://data.austintexas.gov/browse?City-of-Austin_Department-=Austin+Transportation&limitTo=datasets",
img: { src: "/assets/open-data-logo.png", alt: "Open data logo" },
external: true,
},
{
title: "Residential Parking ",
description: "Parking verification for residential parking permits",
href: "/residential-parking",
img: {
src: "/assets/residential-parking.png",
alt: "Residential parking zone map",
},
key: "residential_parking",
},
];
53 changes: 53 additions & 0 deletions page-settings/residential-parking.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
export const US_STATES = [
{ value: "AL", text: "Alabama" },
{ value: "AK", text: "Alaska" },
{ value: "AZ", text: "Arizona" },
{ value: "AR", text: "Arkansas" },
{ value: "CA", text: "California" },
{ value: "CO", text: "Colorado" },
{ value: "CT", text: "Connecticut" },
{ value: "DE", text: "Delaware" },
{ value: "DC", text: "District of Columbia" },
{ value: "FL", text: "Florida" },
{ value: "GA", text: "Georgia" },
{ value: "HI", text: "Hawaii" },
{ value: "ID", text: "Idaho" },
{ value: "IL", text: "Illinois" },
{ value: "IN", text: "Indiana" },
{ value: "IA", text: "Iowa" },
{ value: "KS", text: "Kansas" },
{ value: "KY", text: "Kentucky" },
{ value: "LA", text: "Louisiana" },
{ value: "ME", text: "Maine" },
{ value: "MD", text: "Maryland" },
{ value: "MA", text: "Massachusetts" },
{ value: "MI", text: "Michigan" },
{ value: "MN", text: "Minnesota" },
{ value: "MS", text: "Mississippi" },
{ value: "MO", text: "Missouri" },
{ value: "MT", text: "Montana" },
{ value: "NE", text: "Nebraska" },
{ value: "NV", text: "Nevada" },
{ value: "NH", text: "New Hampshire" },
{ value: "NJ", text: "New Jersey" },
{ value: "NM", text: "New Mexico" },
{ value: "NY", text: "New York" },
{ value: "NC", text: "North Carolina" },
{ value: "ND", text: "North Dakota" },
{ value: "OH", text: "Ohio" },
{ value: "OK", text: "Oklahoma" },
{ value: "OR", text: "Oregon" },
{ value: "PA", text: "Pennsylvania" },
{ value: "RI", text: "Rhode Island" },
{ value: "SC", text: "South Carolina" },
{ value: "SD", text: "South Dakota" },
{ value: "TN", text: "Tennessee" },
{ value: "TX", text: "Texas" },
{ value: "UT", text: "Utah" },
{ value: "VT", text: "Vermont" },
{ value: "VA", text: "Virginia" },
{ value: "WA", text: "Washington" },
{ value: "WV", text: "West Virginia" },
{ value: "WI", text: "Wisconsin" },
{ value: "WY", text: "Wyoming" },
];
9 changes: 9 additions & 0 deletions pages/api/check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const config = {
api: {
externalResolver: true,
},
}

export default function handler(req, res) {
return res.status(200).json({message:"test check"})
}
45 changes: 45 additions & 0 deletions pages/api/passport.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
export const config = {
api: {
externalResolver: true,
},
}

export default function handler(req, res) {
const userQuery = req.query;
fetch(process.env.PASSPORT_AUTH_ENDPOINT, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
grant_type: "client_credentials",
client_id: process.env.PASSPORT_CLIENT_ID,
client_secret: process.env.PASSPORT_CLIENT_SECRET,
audience: "public.api.passportinc.com",
}),
})
.then((response) => {
if (response.status !== 200) {
return res.status(response.status).json();
} else {
return response.json();
}
})
.then((data) => {
const bearerToken = data["access_token"];
let enforcementURL = `${process.env.PASSPORT_ENFORCEMENT_ENDPOINT}?operator_id=${process.env.PASSPORT_OPERATOR_ID}&vehicle_plate=${userQuery.vehicle_plate}`;
// if (form.state.length > 0) {
// queryURL = queryURL + `&vehicle_state=${form.state}`;
// }
return fetch(enforcementURL, {
headers: {
Authorization: `Bearer ${bearerToken}`,
},
});
})
.then((response) => response.json())
.then((data) => {
return res.status(200).json(data);
})
.catch((err) => console.error(err));
}
179 changes: 179 additions & 0 deletions pages/residential-parking.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import { useState } from "react";
import PageHead from "../components/PageHead";
import Nav from "../components/Nav";
import Form from "react-bootstrap/Form";
import Button from "react-bootstrap/Button";
import Container from "react-bootstrap/Container";
import Row from "react-bootstrap/Row";
import Col from "react-bootstrap/Col";
import Spinner from "react-bootstrap/Spinner";
import { FaCheckSquare } from "react-icons/fa";
import { FaTimesCircle } from "react-icons/fa";

import { US_STATES } from "../page-settings/residential-parking";

export default function ResidentialParking({ bearerTokenObj }) {
// todo: consider renaming state to licenseState
const [form, setForm] = useState({
plate: "",
state: "",
});
const [loading, setLoading] = useState(false);
const [result, showResult] = useState(false);
const [permitted, setPermitted] = useState(true);

const checkPermit = () => {
setLoading(true);
let queryURL = `/api/passport?vehicle_plate=${form.plate}`;
if (form.state.length > 0) {
queryURL = queryURL + `&vehicle_state=${form.state}`;
}
fetch(queryURL)
.then((response) => {
console.log(response);
if (response.status !== 200) {
setLoading(false);
// show error?
return response.status + " " + response.statusText;
}
return response.json();
})
.then((data) => {
setLoading(false);
showResult(true);
console.log(data);
if (data.data) {
setPermitted(data.data.length > 0);
} else {
setPermitted(false);
}
})
.catch((err) => console.error(err));
};

const handleChange = (e) => {
showResult(false);
setLoading(false);
setForm({ ...form, [e.target.name]: e.target.value });
};

const handleSubmit = (event) => {
event.preventDefault();
checkPermit();
};

const handleClear = (event) => {
fetch("/api/check")
.then((response) => response.json())
.then((data) => console.log(data));
setForm({
plate: "",
state: "",
});
showResult(false);
setLoading(false);
};

return (
<>
<PageHead
title="Residential Parking"
description="License plate permit lookup for Residential Parking"
pageRoute="/residential-parking"
imageRoute="/assets/traffic-cameras.jpg"
/>
<Nav />
<Container>
<Row>
<Col>
<h5>
Please enter a license plate below to verify parking eligibility.
</h5>
</Col>
</Row>
<Row className="my-3">
<Form>
<Form.Group className="mb-3" controlId="formLicensePlate">
<Row>
<Col className="col col-sm-2">
<Form.Label>License Plate</Form.Label>
<Form.Control
type="text"
name="plate"
value={form.plate}
placeholder="ex: ADR5476"
required
onChange={handleChange}
/>
</Col>
<Col className="col col-sm-1">
<Form.Label>State</Form.Label>
<Form.Select
name="state"
value={form.state}
onChange={handleChange}
>
<option value=""> </option>
{US_STATES.map((state) => (
<option key={state.value} value={state.value}>
{state.text}
</option>
))}
</Form.Select>
</Col>
</Row>
</Form.Group>

<Button
variant="primary"
onClick={handleSubmit}
disabled={!form.plate}
className="me-2"
>
Submit
</Button>
<Button variant="outline-secondary" onClick={handleClear}>
Clear
</Button>
</Form>
</Row>

{loading ? (
<Row className="my-3">
<Spinner animation="border" variant="secondary" />
</Row>
) : (
result && (
<>
<Row className="my-3">
<Col>
<span>
{permitted ? (
<FaCheckSquare color="green" size="1.5em" />
) : (
<FaTimesCircle />
)}
</span>
Vehicle with license plate{" "}
<span className="fw-bold">{form.plate}</span> is{" "}
{!permitted && "not "}
permitted
</Col>
</Row>
<Row>
<p>
For any inquires regarding vehicles that are not permitted
please refer to the Residential Parking Permit{" "}
<a href="https://www.austintexas.gov/department/residential-permit-parking">
webpage
</a>{" "}
frequently asked questions.
</p>
</Row>
</>
)
)}
</Container>
</>
);
}
Binary file added public/assets/residential-parking.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.