commit 5d86aa000c31fd9f1d059ef5e47ffa426e47e87a Author: Ben Mosley Date: Sat Apr 25 12:03:54 2026 -0500 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4636b53 --- /dev/null +++ b/.gitignore @@ -0,0 +1,42 @@ +# Virtual environment +.venv/ +env/ +venv/ + +# Python bytecode and cache +__pycache__/ +*.pyc +*.pyo +*.pyd + +# Flask specific +instance/ +.webassets-cache/ + +# Testing +.pytest_cache/ +.coverage +htmlcov/ + +# Build artifacts +dist/ +build/ +*.egg-info/ + +# Editor specific files (optional, uncomment if applicable) +# .vscode/ +# .idea/ +# *.sublime-project +# *.sublime-workspace + +# Database files (if using a local SQLite database) +*.db +*.sqlite +*.sqlite3 + +# Log files +*.log + +# Sensitive files (e.g., environment variables) +.env +ga_key.json diff --git a/About.html b/About.html new file mode 100644 index 0000000..f385358 --- /dev/null +++ b/About.html @@ -0,0 +1,131 @@ + + + + + + + + + + + + About + + + + + + + + + + + + + + + + + + + + + + + +
+

About Us

+
+ + + +
+
+
+

Mission Statement

+

+ We at Thors Hammer Electrical strive to be the best in the field. We proudly serve Levelland and the surrounding areas.

+ + +

Remember, at Thor's Hammer Electrical, we put the power back in the panel!

+
+
+
+ + + +
+
+
+

Company History

+

+ Thor's Hammer Electrical LLC was founded in April 2023. We have over 20 years of electrical experience. We are a small company with family values.

+ +

When you choose Thors Hammer Electrical for your electrical needs, you become part of the family.

+
+
+
+ + + +
+
+
+

Our Team Includes:

+ +
+ +

Leonard Johnson:

+

Master Electrician, Company Owner and Operator

+ +
+ +

Makayla Johnson:

+

Electrician's Apprentice

+ +
+ +

Robert Johnson:

+

Electrician's Apprentice

+
+
+
+ + + + + + + + diff --git a/Contact.html b/Contact.html new file mode 100644 index 0000000..eef2e00 --- /dev/null +++ b/Contact.html @@ -0,0 +1,54 @@ + + + + + + + Contact + + + + + + + + + + + + + + + +
+ +
diff --git a/Review.html b/Review.html new file mode 100644 index 0000000..1785ec7 --- /dev/null +++ b/Review.html @@ -0,0 +1,97 @@ + + + + + + + + + + + + Customer Reviews + + + + + + + + + + + + + + + + + + + + + +
+

See What Our Customers Are Saying!

+

Your reviews will also be featured here on our website. We appreciate your business and your feedback!

+
+ +
+ + +
+
+
+ + + + +
+ + + + + + + diff --git a/Services.html b/Services.html new file mode 100644 index 0000000..3931ec7 --- /dev/null +++ b/Services.html @@ -0,0 +1,122 @@ + + + + + + + + + + + + Services + + + + + + + + + + + + + + + + + + + + + +
+

Our Services

+
+

Thor's Hammer Electrical provides a diverse spread of services.

+
+ + +
+
+
+

Residential

+

+ Our residential services are the bread and butter of Thor's Hammer. We live to serve our community members and make sure their needs are met. +

+
+
+
+ + +
+
+
+

Commercial

+

+ Part of serving your community is ensuring the needs of both the people and their businesses are met. Having spent multiple years servicing commercial products, Thor's Hammer is your go-to commercial contractor! +

+
+
+
+ + + +
+
+
+

Here are some specific jobs completed by Thor's Hammer in the past.

+
+
(Pictures coming soon!)
+
+
    +
  • Christmas Lights
  • +
  • Cat5, Cat6, and Cat6a Network Installation
  • +
  • Security Camera Installation
  • +
  • Flood Light Installation
  • +
+
+
+
+ + + + + + + + diff --git a/admin.html b/admin.html new file mode 100644 index 0000000..4ab10dc --- /dev/null +++ b/admin.html @@ -0,0 +1,131 @@ + + + + + + Admin Panel - Work Orders + + + + + + + +
+

Thor's Hammer Electrical - Admin Panel

+
+ + +
+ + + + + + + + + + + + + + + + + {% for order in work_orders %} + + + + + + + + + + + + + {% endfor %} + +
IDNameJobAddressCityStateZipcodePhoneSubmitted AtActions
{{ order[0] }} {{ order[1] }} {{ order[2] }} {{ order[3] }} {{ order[4] }} {{ order[5] }} {{ order[6] }} {{ order[7] }} {{ order[8] }} + +
+ +
+ + +
+ +
+
+
+ + +
+ View Completed Jobs + + +
+ +
+
+ +

Website Analytics

+
+
+
+
+

Total Visitors

+

Loading...

+
+
+
+ +
+
+
+

Page Views

+

Loading...

+
+
+
+ +
+
+
+

Most Visited Page

+

Loading...

+
+
+
+
+ + + + + + + + + diff --git a/app.py b/app.py new file mode 100644 index 0000000..ca1943a --- /dev/null +++ b/app.py @@ -0,0 +1,320 @@ +import os +from flask import Flask, render_template, request, redirect, url_for, session, flash, g, jsonify +from dotenv import load_dotenv +import sqlite3 +from datetime import timedelta +import requests +from google.oauth2 import service_account +from googleapiclient.discovery import build +import json +import logging +load_dotenv() + +app = Flask(__name__) +app.secret_key = os.getenv('FLASK_SECRET_KEY', os.urandom(24)) +app.permanent_session_lifetime = timedelta(minutes=30) +app.config['SESSION_COOKIE_PATH'] = '/' + +USERNAME = os.getenv('FLASK_LOGIN_USER') +PASSWORD = os.getenv('FLASK_LOGIN_PASSWORD') +DATABASE = 'work_orders.db' + +PUSHOVER_API_TOKEN = os.getenv('PUSHOVER_API_TOKEN') +PUSHOVER_USER_KEY = os.getenv('PUSHOVER_USER_KEY') + +GA_PROPERTY_ID = os.getenv('GA_PROPERTY_ID') +GA_CREDENTIALS = 'ga_key.json' + +RECAPTCHA_SITE_KEY = os.getenv('RECAPTCHA_SITE_KEY') +RECAPTCHA_SECRET_KEY = os.getenv('RECAPTCHA_SECRET_KEY') + +logging.basicConfig( + filename='ga4_debug.log', + level=logging.DEBUG, + format='%(asctime)s - %(levelname)s - %(message)s' +) + + +def get_db(): + db = getattr(g, '_database', None) + if db is None: + db = g._database = sqlite3.connect(DATABASE) + return db + + +@app.teardown_appcontext +def close_connection(exception): + db = getattr(g, '_database', None) + if db is not None: + db.close() + + +def init_db(): + with app.app_context(): + db = get_db() + db.execute('''CREATE TABLE IF NOT EXISTS orders ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + job TEXT NOT NULL, + address TEXT NOT NULL, + city TEXT NOT NULL, + state TEXT NOT NULL, + zipcode INTEGER NOT NULL, + phone TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + );''') + db.execute('''CREATE TABLE IF NOT EXISTS completed_orders ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + job TEXT NOT NULL, + address TEXT NOT NULL, + city TEXT NOT NULL, + state TEXT NOT NULL, + zipcode INTEGER NOT NULL, + phone TEXT NOT NULL, + completed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + );''') + db.commit() + + +# ── Public pages ────────────────────────────────────────────── + +@app.route('/') +def index(): + return render_template('index.html') + + +@app.route('/about') +def about(): + return render_template('about.html') + + +@app.route('/services') +def services(): + return render_template('services.html') + + +@app.route('/reviews') +def reviews(): + return render_template('reviews.html') + + +@app.route('/contact') +def contact(): + return render_template('contact.html') + + +def verify_recaptcha(token): + if not RECAPTCHA_SECRET_KEY: + return True # skip check if not configured yet + try: + resp = requests.post( + 'https://www.google.com/recaptcha/api/siteverify', + data={'secret': RECAPTCHA_SECRET_KEY, 'response': token}, + timeout=5, + ) + result = resp.json() + return result.get('success') and result.get('score', 0) >= 0.5 + except Exception: + return True # fail open if Google is unreachable + + +@app.route('/work-order') +def work_order(): + return render_template('work_order.html', recaptcha_site_key=RECAPTCHA_SITE_KEY) + + +# ── Work order submission ───────────────────────────────────── + +@app.route('/submit', methods=['POST']) +def submit(): + # Honeypot: real users never fill this field; bots usually do + if request.form.get('website'): + session['form_submitted'] = True + return redirect(url_for('success')) # silent reject — bot thinks it worked + + # reCAPTCHA v3 score check + token = request.form.get('g-recaptcha-response', '') + if not verify_recaptcha(token): + session['form_submitted'] = True + return redirect(url_for('failure')) + + try: + name = request.form.get('name') + job = request.form.get('job') + address = request.form.get('address') + city = request.form.get('city') + state = request.form.get('state') + zipcode = request.form.get('zipcode') + phone = request.form.get('phone') + + conn = get_db() + conn.execute('''INSERT INTO orders (name, job, address, city, state, zipcode, phone) + VALUES (?, ?, ?, ?, ?, ?, ?)''', + (name, job, address, city, state, zipcode, phone)) + conn.commit() + + send_push_notification(name, job) + session['form_submitted'] = True + return redirect(url_for('success')) + + except Exception as e: + session['form_submitted'] = True + return redirect(url_for('failure')) + + +@app.route('/success') +def success(): + if not session.pop('form_submitted', None): + return redirect(url_for('work_order')) + return render_template('success.html') + + +@app.route('/failure') +def failure(): + if not session.pop('form_submitted', None): + return redirect(url_for('work_order')) + return render_template('failure.html') + + +# ── Auth ────────────────────────────────────────────────────── + +@app.route('/login', methods=['GET', 'POST']) +def login(): + if request.method == 'POST': + username = request.form['username'] + password = request.form['password'] + if username == USERNAME and password == PASSWORD: + session.permanent = True + session['logged_in'] = True + return redirect(url_for('admin')) + else: + flash('Invalid username or password.', 'danger') + return render_template('login.html') + + +@app.route('/logout', methods=['GET', 'POST']) +def logout(): + session.pop('logged_in', None) + flash('You have been logged out.') + return redirect(url_for('index')) + + +# ── Admin ───────────────────────────────────────────────────── + +@app.route('/admin') +def admin(): + if not session.get('logged_in'): + return redirect(url_for('login')) + conn = get_db() + orders = conn.execute('SELECT * FROM orders').fetchall() + return render_template('admin.html', work_orders=orders) + + +@app.route('/delete_order/', methods=['POST']) +def delete_order(order_id): + if not session.get('logged_in'): + return redirect(url_for('login')) + try: + db = get_db() + db.execute('DELETE FROM orders WHERE id = ?', (order_id,)) + db.commit() + flash('Work order deleted.', 'success') + except Exception as e: + flash(f'Error deleting work order: {str(e)}', 'danger') + return redirect(url_for('admin')) + + +@app.route('/mark_complete/', methods=['POST']) +def mark_complete(order_id): + if not session.get('logged_in'): + return redirect(url_for('login')) + try: + db = get_db() + order = db.execute('SELECT * FROM orders WHERE id = ?', (order_id,)).fetchone() + if order: + db.execute('''INSERT INTO completed_orders (name, job, address, city, state, zipcode, phone) + VALUES (?, ?, ?, ?, ?, ?, ?)''', + (order[1], order[2], order[3], order[4], order[5], order[6], order[7])) + db.execute('DELETE FROM orders WHERE id = ?', (order_id,)) + db.commit() + flash('Work order marked as complete.', 'success') + else: + flash('Work order not found.', 'danger') + except Exception as e: + flash(f'Error: {str(e)}', 'danger') + return redirect(url_for('admin')) + + +@app.route('/completed_jobs') +def completed_jobs(): + if not session.get('logged_in'): + return redirect(url_for('login')) + db = get_db() + jobs = db.execute('SELECT * FROM completed_orders').fetchall() + return render_template('completed_jobs.html', completed_jobs=jobs) + + +# ── Analytics ───────────────────────────────────────────────── + +def get_ga4_data(): + try: + credentials = service_account.Credentials.from_service_account_file( + GA_CREDENTIALS, scopes=["https://www.googleapis.com/auth/analytics.readonly"] + ) + analytics = build("analyticsdata", "v1beta", credentials=credentials) + + response = analytics.properties().runReport( + property=f"properties/{int(GA_PROPERTY_ID)}", + body={ + "dateRanges": [{"startDate": "7daysAgo", "endDate": "yesterday"}], + "metrics": [{"name": "totalUsers"}, {"name": "screenPageViews"}], + "dimensions": [{"name": "pagePath"}], + "limit": 1, + }, + ).execute() + + logging.debug("Full GA4 API Response: %s", json.dumps(response, indent=2)) + + rows = response.get("rows", []) + if not rows: + return {"total_users": "0", "total_pageviews": "0", "top_page": "N/A"} + + top_page = rows[0]["dimensionValues"][0]["value"] + metric_values = rows[0]["metricValues"] + total_users = metric_values[0]["value"] if len(metric_values) > 0 else "0" + total_pageviews = metric_values[1]["value"] if len(metric_values) > 1 else "0" + + return {"total_users": total_users, "total_pageviews": total_pageviews, "top_page": top_page} + + except Exception as e: + logging.error("Google Analytics API Error: %s", str(e)) + return {"total_users": "0", "total_pageviews": "0", "top_page": "N/A"} + + +@app.route('/analytics') +def analytics(): + if not session.get('logged_in'): + return redirect(url_for('login')) + return jsonify(get_ga4_data()) + + +# ── Notifications ───────────────────────────────────────────── + +def send_push_notification(name, job): + if not PUSHOVER_API_TOKEN or not PUSHOVER_USER_KEY: + return + message = f"New Work Order:\nName: {name}\nJob: {job}" + data = { + "token": PUSHOVER_API_TOKEN, + "user": PUSHOVER_USER_KEY, + "message": message, + } + response = requests.post("https://api.pushover.net/1/messages.json", data=data) + if response.status_code != 200: + print(f"Push notification failed: {response.status_code} - {response.text}") + + +if __name__ == '__main__': + init_db() + app.run(debug=True) diff --git a/completed_jobs.html b/completed_jobs.html new file mode 100644 index 0000000..f0bcdaf --- /dev/null +++ b/completed_jobs.html @@ -0,0 +1,61 @@ + + + + + + Admin Panel - Completed Jobs + + + + + + + +
+

Thor's Hammer Electrical - Completed Jobs

+
+ + +
+ + + + + + + + + + + + + + + + {% for job in completed_jobs %} + + + + + + + + + + + + {% endfor %} + +
IDNameJobAddressCityStateZipcodePhoneCompleted At
{{ job[0] }} {{ job[1] }} {{ job[2] }} {{ job[3] }} {{ job[4] }} {{ job[5] }} {{ job[6] }} {{ job[7] }} {{ job[8] }}
+ + + + + + + diff --git a/dash.html b/dash.html new file mode 100644 index 0000000..59c2bad --- /dev/null +++ b/dash.html @@ -0,0 +1,62 @@ + + + + + + Website Analytics Dashboard + + + +
+

Website Analytics Dashboard

+ +
+ +
+
+
+

Total Visitors

+

Loading...

+
+
+
+ + +
+
+
+

Page Views

+

Loading...

+
+
+
+ + +
+
+
+

Most Visited Page

+

Loading...

+
+
+
+
+
+ + + + + + + diff --git a/failure.html b/failure.html new file mode 100644 index 0000000..754a0fb --- /dev/null +++ b/failure.html @@ -0,0 +1,74 @@ + + + + + + + + + + + Work Order Form + + + + + + + + + + + + + + + + + + + +
+
+
+

Something went wrong. Please try again!

+
+ +
+ +
+ +
+
+
+ diff --git a/index.html b/index.html new file mode 100644 index 0000000..a1a68e8 --- /dev/null +++ b/index.html @@ -0,0 +1,93 @@ + + + + + + + + + Thor's Hammer Electrical LLC + + + + + + + + + + + + + + + + + + + + +
+

Welcome to the Thor's Hammer Official Website!

+
+ +
+ License Image +
+ +
+
+ Thor's Hammer Electrical LLC is a local electrical services company based in Levelland, Texas. +


+ Owned and operated by Leonard Johnson, Thor's Hammer Electrical LLC looks to serve customers far and wide, big and small. +
+
+ + + + + + + + diff --git a/login.html b/login.html new file mode 100644 index 0000000..a8eeef7 --- /dev/null +++ b/login.html @@ -0,0 +1,67 @@ + + + + + + + Login + + + + + + + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..456b28b --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +flask +python-dotenv +requests +google-auth +google-api-python-client +gunicorn diff --git a/static/images/License.jpg b/static/images/License.jpg new file mode 100644 index 0000000..84adadc Binary files /dev/null and b/static/images/License.jpg differ diff --git a/static/images/Logo.png b/static/images/Logo.png new file mode 100644 index 0000000..4244d4e Binary files /dev/null and b/static/images/Logo.png differ diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..6136311 --- /dev/null +++ b/styles.css @@ -0,0 +1,11 @@ + +.bg-dark-gray { + background-color: #333333; /* Darker Gray */ + } + + body { + background-color: #000000; /* Black background for body */ +} + + + diff --git a/success.html b/success.html new file mode 100644 index 0000000..18c5aa5 --- /dev/null +++ b/success.html @@ -0,0 +1,74 @@ + + + + + + + + + + + Work Order Form + + + + + + + + + + + + + + + + + + + +
+
+
+

Success! Thank you for choosing Thor's Hammer

+
+ +
+ +
+ +
+
+
+ diff --git a/templates/about.html b/templates/about.html new file mode 100644 index 0000000..bedbfb2 --- /dev/null +++ b/templates/about.html @@ -0,0 +1,135 @@ +{% extends "base.html" %} +{% block title %}About — Thor's Hammer Electrical LLC{% endblock %} + +{% block content %} + + +
+
+
+

Our Story

+

ABOUT US

+
+
+ + +
+
+
+
+
+ +
+

Mission Statement

+
+

+ We at Thor's Hammer Electrical strive to be the best in the field. We proudly serve + Levelland and the surrounding areas with dedication, integrity, and craftsmanship. +

+

+ "At Thor's Hammer Electrical, we put the power back in the panel!" +

+
+
+
+ + +
+
+
+
+
+ +
+

Company History

+
+

+ Thor's Hammer Electrical LLC was founded in April 2023. We bring over 20 years of + electrical experience to every project, operating as a small company with big family values. +

+

+ When you choose Thor's Hammer Electrical for your electrical needs, + you don't just get a contractor — you become part of the family. +

+
+
+
+ + +
+
+

The Crew

+

Our Team

+ +
+ + +
+
+ +
+

Leonard Johnson

+

Master Electrician

+

Company Owner & Operator
20+ Years Experience

+
+ + +
+
+ +
+

Makayla Johnson

+

Electrician's Apprentice

+

Team Member

+
+ + +
+
+ +
+

Robert Johnson

+

Electrician's Apprentice

+

Team Member

+
+ + +
+
+ +
+

Benjamin Mosley

+

IT & Web

+

+ Benny's House +

+
+ +
+
+
+ + +
+

Need Electrical Work Done?

+

Submit a work order and we'll be in touch.

+ + SUBMIT WORK ORDER + +
+ +{% endblock %} diff --git a/templates/admin.html b/templates/admin.html new file mode 100644 index 0000000..a5b21ff --- /dev/null +++ b/templates/admin.html @@ -0,0 +1,171 @@ + + + + + + Admin Panel — Thor's Hammer Electrical + + + + + + + + + + + +
+
+
+ Logo +

+ Thor's Hammer + · Admin Panel +

+
+
+ + Completed Jobs + +
+ +
+
+
+
+ +
+ + + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} +
+ {% for category, message in messages %} +
+ {{ message }} +
+ {% endfor %} +
+ {% endif %} + {% endwith %} + + +
+
+

Total Visitors (7d)

+

+
+
+

Page Views (7d)

+

+
+
+

Top Page (7d)

+

+
+
+ + +
+
+
+

Active Work Orders

+

{{ work_orders | length }} order(s) pending

+
+
+ + {% if work_orders %} +
+ + + + + + + + + + + + + + {% for order in work_orders %} + + + + + + + + + + {% endfor %} + +
IDNameJobAddressPhoneSubmittedActions
#{{ order[0] }}{{ order[1] }} + {{ order[2] }} + + {{ order[3] }}, {{ order[4] }}, {{ order[5] }} {{ order[6] }} + {{ order[7] }}{{ order[8] }} +
+
+ +
+
+ +
+
+
+
+ {% else %} +
+ +

No active work orders

+

New orders will appear here

+
+ {% endif %} +
+ +
+ + + + + diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..5863afc --- /dev/null +++ b/templates/base.html @@ -0,0 +1,180 @@ + + + + + + {% block title %}Thor's Hammer Electrical LLC{% endblock %} + + + + + + + + + + + + + + + + + + + + + + {% block extra_head %}{% endblock %} + + + + + + + + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} +
+ {% for category, message in messages %} +
+ {{ message }} +
+ {% endfor %} +
+ {% endif %} + {% endwith %} + + + {% block content %}{% endblock %} + + + + + + {% block extra_scripts %}{% endblock %} + + diff --git a/templates/completed_jobs.html b/templates/completed_jobs.html new file mode 100644 index 0000000..7821ae9 --- /dev/null +++ b/templates/completed_jobs.html @@ -0,0 +1,121 @@ + + + + + + Completed Jobs — Thor's Hammer Electrical + + + + + + + + + + + +
+
+
+ Logo +

+ Thor's Hammer + · Completed Jobs +

+
+
+ + ← Active Orders + +
+ +
+
+
+
+ +
+ + + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} +
+ {% for category, message in messages %} +
+ {{ message }} +
+ {% endfor %} +
+ {% endif %} + {% endwith %} + + +
+
+

Completed Jobs

+

{{ completed_jobs | length }} job(s) completed

+
+ + {% if completed_jobs %} +
+ + + + + + + + + + + + + {% for job in completed_jobs %} + + + + + + + + + {% endfor %} + +
IDNameJobAddressPhoneCompleted
#{{ job[0] }}{{ job[1] }} + {{ job[2] }} + + {{ job[3] }}, {{ job[4] }}, {{ job[5] }} {{ job[6] }} + {{ job[7] }} + + + {{ job[8] }} + +
+
+ {% else %} +
+ +

No completed jobs yet

+

Jobs marked as complete will appear here

+
+ {% endif %} +
+ +
+ + + diff --git a/templates/contact.html b/templates/contact.html new file mode 100644 index 0000000..677d4d0 --- /dev/null +++ b/templates/contact.html @@ -0,0 +1,64 @@ +{% extends "base.html" %} +{% block title %}Contact — Thor's Hammer Electrical LLC{% endblock %} + +{% block content %} + + +
+
+
+

Get In Touch

+

CONTACT US

+

+ Have a question or need to reach us directly? Fill out the form below and we'll get back to you. +

+
+
+ + +
+
+ +
+
+ +

Location

+

Levelland, Texas

+
+
+ +

Work Orders

+

+ + Submit here → + +

+
+
+ +

Response Time

+

We respond promptly

+
+
+ + +
+ +

Ready to Get Work Done?

+

+ Submit a work order and we'll be notified right away. Fill out your name, job description, + and address and we'll follow up with you shortly. +

+ + SUBMIT WORK ORDER + +
+ +
+
+ +{% endblock %} diff --git a/templates/failure.html b/templates/failure.html new file mode 100644 index 0000000..ba4dc68 --- /dev/null +++ b/templates/failure.html @@ -0,0 +1,46 @@ +{% extends "base.html" %} +{% block title %}Something Went Wrong — Thor's Hammer Electrical LLC{% endblock %} + +{% block content %} + +
+
+ +
+ + +
+ +
+ +

+ Something Went Wrong +

+

+ We couldn't process your work order +

+

+ We're sorry for the inconvenience. Please try submitting your order again. + If the issue persists, feel free to contact us directly. +

+ + +
+ +
+
+ +{% endblock %} diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..8b0895f --- /dev/null +++ b/templates/index.html @@ -0,0 +1,213 @@ +{% extends "base.html" %} +{% block title %}Thor's Hammer Electrical LLC — Levelland, TX{% endblock %} + +{% block content %} + + +
+ + +
+ + +
+ +
+ +
+ +
+ +

+ THOR'S HAMMER +

+

+ ELECTRICAL LLC +

+ +

+ Levelland, Texas's Premier Electrical Contractor +

+

+ Residential & Commercial · Licensed & Insured · 20+ Years Experience +

+ + +
+ + +
+ + + +
+
+ + +
+
+
+
+

20+

+

Years of Experience

+
+
+

100%

+

Licensed & Insured

+
+
+

Local

+

Levelland, Texas

+
+
+
+
+ + +
+
+

Certified & Trusted

+

Our License

+
+ Electrical License +
+
+
+ + +
+
+
+
+

Who We Are

+

+ Powering Levelland
+ Since 2023 +

+

+ Thor's Hammer Electrical LLC is a locally owned and operated electrical services company + based in Levelland, Texas. Owned by Master Electrician Leonard Johnson, we bring + over 20 years of hands-on experience to every job. +

+

+ We put the power back in the panel — and we treat every customer like family. +

+ + LEARN MORE + + + + +
+ + +
+ {% set features = [ + ('fa-bolt', 'Residential', 'Home wiring, panels, lighting & more'), + ('fa-industry', 'Commercial', 'Business & industrial electrical work'), + ('fa-shield-halved', 'Licensed', 'Fully licensed Master Electrician'), + ('fa-handshake', 'Family Values', 'You become part of our family'), + ] %} + {% for icon, title, desc in features %} +
+ +

{{ title }}

+

{{ desc }}

+
+ {% endfor %} +
+
+
+
+ + +
+
+

What We Do

+

Our Services

+

+ From residential homes to commercial businesses, Thor's Hammer has you covered. +

+ +
+
+
+ +
+

Residential

+

+ Our residential services are the bread and butter of Thor's Hammer. We live to serve + our community members and ensure every home is safe and powered. +

+
+
+
+ +
+

Commercial

+

+ Having spent years servicing commercial properties, Thor's Hammer is your go-to + commercial electrical contractor for businesses of all sizes. +

+
+
+ + + SEE ALL SERVICES + + + + +
+
+ + +
+
+
+
+
+ +

+ Ready to Get Started? +

+

+ Submit your work order today and we'll get back to you promptly. +

+ + SUBMIT WORK ORDER + +
+
+
+
+ +{% endblock %} diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 0000000..0b3f318 --- /dev/null +++ b/templates/login.html @@ -0,0 +1,89 @@ + + + + + + Admin Login — Thor's Hammer Electrical + + + + + + + + + +
+ + +
+ Logo +

ADMIN LOGIN

+

Thor's Hammer Electrical

+
+ + + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} +
+ {% for category, message in messages %} +
+ {{ message }} +
+ {% endfor %} +
+ {% endif %} + {% endwith %} + + +
+
+ +
+ + +
+ +
+ + +
+ + +
+
+ +

+ + ← Back to Website + +

+
+ + + diff --git a/templates/reviews.html b/templates/reviews.html new file mode 100644 index 0000000..8958bc4 --- /dev/null +++ b/templates/reviews.html @@ -0,0 +1,75 @@ +{% extends "base.html" %} +{% block title %}Reviews — Thor's Hammer Electrical LLC{% endblock %} + +{% block content %} + + +
+
+
+

Happy Customers

+

REVIEWS

+

+ See what our customers are saying. Your reviews may be featured here too! +

+
+
+ + +
+
+ +
+

+ We appreciate your business and your feedback. Reviews from our Facebook page are shown below. +

+
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+ +

Leave Us a Review!

+

+ Your feedback means the world to us. Leave a review on Facebook and we may feature it here. +

+ + LEAVE A REVIEW + +
+
+
+ +{% endblock %} diff --git a/templates/services.html b/templates/services.html new file mode 100644 index 0000000..3009d80 --- /dev/null +++ b/templates/services.html @@ -0,0 +1,110 @@ +{% extends "base.html" %} +{% block title %}Services — Thor's Hammer Electrical LLC{% endblock %} + +{% block content %} + + +
+
+
+

What We Offer

+

OUR SERVICES

+

+ Thor's Hammer Electrical provides a diverse range of services for homes and businesses. +

+
+
+ + +
+
+ + +
+
+ +
+

Residential

+

+ Our residential services are the bread and butter of Thor's Hammer. We live to serve + our community members and make sure their homes are safe, functional, and up to code. +

+
    + {% for item in ['Panel upgrades & repairs', 'Outlet & switch installation', 'Lighting installation', 'Wiring & rewiring', 'Ceiling fan installation', 'Christmas light installation', 'Security camera installation'] %} +
  • + {{ item }} +
  • + {% endfor %} +
+
+ + +
+
+ +
+

Commercial

+

+ Part of serving your community is ensuring the needs of businesses are met. Having spent + multiple years servicing commercial properties, Thor's Hammer is your go-to commercial + electrical contractor. +

+
    + {% for item in ['Commercial wiring', 'Electrical inspections', 'Lighting systems', 'Power distribution', 'Code compliance'] %} +
  • + {{ item }} +
  • + {% endfor %} +
+
+
+
+ + +
+
+
+

Our Work

+

Jobs We've Completed

+
+ +
+ {% set jobs = [ + ('fa-tree', 'Christmas Lights', 'Seasonal decorative lighting installation'), + ('fa-network-wired', 'Network Cabling', 'Cat5, Cat6, and Cat6a Network Installation'), + ('fa-camera', 'Security Cameras', 'Security camera system installation'), + ('fa-lightbulb', 'Flood Lights', 'Outdoor flood light installation'), + ] %} + {% for icon, title, desc in jobs %} +
+ +

{{ title }}

+

{{ desc }}

+
+ {% endfor %} +
+ +
+

📸 Project photos coming soon!

+
+
+
+ + +
+

Need Any of These Services?

+

We serve Levelland, TX and surrounding areas. Submit a work order today.

+ + SUBMIT WORK ORDER + +
+ +{% endblock %} diff --git a/templates/success.html b/templates/success.html new file mode 100644 index 0000000..efc763f --- /dev/null +++ b/templates/success.html @@ -0,0 +1,46 @@ +{% extends "base.html" %} +{% block title %}Order Submitted — Thor's Hammer Electrical LLC{% endblock %} + +{% block content %} + +
+
+ +
+ + +
+ +
+ +

+ Order Submitted! +

+

+ Thank you for choosing Thor's Hammer Electrical +

+

+ We've received your work order and will be in touch shortly. + We appreciate your business! +

+ + +
+ +
+
+ +{% endblock %} diff --git a/templates/work_order.html b/templates/work_order.html new file mode 100644 index 0000000..0b26d36 --- /dev/null +++ b/templates/work_order.html @@ -0,0 +1,171 @@ +{% extends "base.html" %} +{% block title %}Submit Work Order — Thor's Hammer Electrical LLC{% endblock %} + +{% if recaptcha_site_key %} +{% block extra_head %} + +{% endblock %} +{% endif %} + +{% block content %} + + +
+
+
+

Get Service

+

WORK ORDER

+

+ Fill out the form below and we'll be notified immediately. We'll follow up with you shortly. +

+
+
+ + +
+
+ +
+ +
+
+ +
+

New Work Order

+

All fields are required

+
+
+
+ + +
+ + + + + + + + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + +
+ + +
+ +

+ We'll receive a notification immediately and follow up with you. +

+
+
+
+ +
+
+ +{% endblock %} + +{% if recaptcha_site_key %} +{% block extra_scripts %} + +{% endblock %} +{% endif %} diff --git a/wsgi.py b/wsgi.py new file mode 100644 index 0000000..afeaa0a --- /dev/null +++ b/wsgi.py @@ -0,0 +1,5 @@ +from app import app + +if __name__ == '__main__': + app.run() +