Thu's Project Guide
Project: OPT Pal — H-1B Employer Data Hub Category: Web App (Flask) + Data Science Last updated: April 23
Note: This guide reflects the latest state of your project repo. It may not match the most up-to-date version if you've worked since.
In class today we lined up two polish items before Checkpoint 3: a proper landing page at / and turning the state quiz step into checkboxes showing only states that actually appear in the data.
Phase 1: Landing page at /
Objective
Replace the redirect-to-quiz with a real home page that explains what OPT Pal is, has a CTA (Call To Action) button to start the quiz, and shows credits in a footer on every page.
Instructions
Hints
app.py — update the home route:
@app.route("/")
def home():
return render_template("home.html", title="OPT Pal")
templates/home.html:
{% extends "base.html" %} {% block content %}
<section class="panel hero">
<h1>OPT Pal</h1>
<p class="lede">
Find H-1B-friendly employers that actually hire in your industry. OPT Pal
turns public USCIS approval data into a simple quiz — answer 4 questions and
get a dashboard of employers that match.
</p>
<h2>What this is about</h2>
<p>
Every year USCIS publishes the list of employers who sponsored H-1B
petitions. That dataset is huge and hard to read. OPT Pal filters it by
industry, state, city, and company size so you can focus on the employers
that fit you.
</p>
<a class="btn btn-primary" href="{{ url_for('quiz', step=1) }}">
Find employers
</a>
</section>
{% endblock %}
templates/base.html — add a footer inside <body>, after the main content block:
<footer class="site-footer">
<p>
Built by Thu Huynh for CSC 121 Final Project. Data source:
<a
href="https://www.uscis.gov/tools/reports-and-studies/h-1b-employer-data-hub"
>
USCIS H-1B Employer Data Hub
</a>
.
</p>
</footer>
Since every page extends base.html, the footer will show up automatically on the quiz and dashboard too.
Phase 2: State checkboxes (dataset-only, multi-select)
Objective
On quiz step 2, show a checkbox for every state that appears in the data and let the user pick more than one. Pass the picks through the rest of the quiz and into the dashboard filter.
Instructions
Hints
search.py — handle a list in _build_where():
state = filters.get("state")
if isinstance(state, list) and state:
placeholders = ", ".join("?" for _ in state)
clauses.append(f"state IN ({placeholders})")
params.extend(s.strip().upper() for s in state)
elif isinstance(state, str) and state:
clauses.append("state = ?")
params.append(state.strip().upper())
unique_states() already uses SELECT DISTINCT state FROM employers, so the checkbox list is automatically "just states present in the dataset" — no extra filtering needed.
app.py — read state as a list:
filters = {
"industry": request.args.get("industry", ""),
"state": request.args.getlist("state"),
"city": request.args.get("city", ""),
"size": request.args.get("size", ""),
}
Use the same filters dict shape in both /quiz and /dashboard so the rest of your code doesn't change.
templates/quiz.html step 2 — checkboxes:
{% elif step == 2 %}
<form method="get" action="{{ url_for('quiz') }}">
<input type="hidden" name="step" value="3" />
<input type="hidden" name="industry" value="{{ answers.industry }}" />
<fieldset>
<legend>Which states are you open to?</legend>
{% for s in states %}
<label class="state-check">
<input
type="checkbox"
name="state"
value="{{ s }}"
{%
if
s
in
answers.state
%}checked{%
endif
%}
/>
{{ s }}
</label>
{% endfor %}
</fieldset>
<button type="submit">Next</button>
</form>
Passing state forward in later steps — one hidden input per selected state:
{% for s in answers.state %}
<input type="hidden" name="state" value="{{ s }}" />
{% endfor %}
Drop that block into step 3, step 4, and any other form that forwards answers. Flask's request.args.getlist("state") reads them all back as a list.