Compare commits
10 Commits
438e493ac2
...
a4188c623d
| Author | SHA1 | Date | |
|---|---|---|---|
| a4188c623d | |||
| 942d341527 | |||
| c920d266f2 | |||
| 64781d1697 | |||
| 8e79c1b70b | |||
| c23209dd7a | |||
| bff3e510ff | |||
| 18c26e18ba | |||
| 2a1b61b79a | |||
| 0d7ab472ca |
135
.gitignore
vendored
@@ -16,4 +16,139 @@ vite.config.ts.timestamp-*
|
||||
/.idea/inspectionProfiles/profiles_settings.xml
|
||||
/.idea/inspectionProfiles/Project_Default.xml
|
||||
/.idea/vcs.xml
|
||||
*.pyc
|
||||
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Python template
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.idea
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
*.iml
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
|
||||
db.sqlite3
|
||||
|
||||
# Flask stuff:
|
||||
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
venvwindows/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
app/package.json
|
||||
app/package-lock.json
|
||||
.vscode/
|
||||
clearnet.ini
|
||||
|
||||
rsync_svg.txt
|
||||
setup/
|
||||
word_seeds.txt
|
||||
workspace.code-workspace
|
||||
|
||||
/static/images/
|
||||
/static/fonts/
|
||||
/images/*
|
||||
|
||||
|
||||
instance/config.py
|
||||
.idea/
|
||||
/passwords.py
|
||||
|
||||
getnewitems.py
|
||||
helperfunctions/
|
||||
test.py
|
||||
tools/
|
||||
nginx.txt
|
||||
app/node_modules/
|
||||
|
||||
*.pyc
|
||||
1567
package-lock.json
generated
Normal file → Executable file
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "auburnoil",
|
||||
"name": "newenglandbio",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
BIN
public/favicon.ico
Executable file
|
After Width: | Height: | Size: 318 B |
0
public/robots.txt
Normal file → Executable file
@@ -2,7 +2,7 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<link rel="icon" href="/images/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width , initial-scale=1.0" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
|
||||
@@ -2,3 +2,20 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
.btn-blue-oil {
|
||||
background-color: #14368f;
|
||||
}
|
||||
.bg-blue-oil {
|
||||
background-color: #14368f;
|
||||
}
|
||||
.text-blue-oil {
|
||||
color: #14368f;
|
||||
}
|
||||
|
||||
.bg-orange-oil {
|
||||
background-color: #ff6600;
|
||||
}
|
||||
.text-orange-oil {
|
||||
color: #ff6600;
|
||||
}
|
||||
BIN
src/favicon.png
Executable file
|
After Width: | Height: | Size: 318 B |
107
src/lib/types/types.ts
Normal file → Executable file
@@ -1,97 +1,20 @@
|
||||
|
||||
|
||||
export type oilprice = {
|
||||
ok: boolean
|
||||
todays_price: string;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export type RegisterRequest = {
|
||||
email: string;
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export type company = {
|
||||
ok: boolean
|
||||
company_name: string;
|
||||
company_phone_number: string;
|
||||
|
||||
export type LoginRequest = {
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
|
||||
export type deliverytype = {
|
||||
ok: boolean
|
||||
id: number;
|
||||
customer_id: string;
|
||||
customer_name: string;
|
||||
customer_address: string;
|
||||
customer_town: string;
|
||||
customer_state: number;
|
||||
customer_zip: string;
|
||||
gallons_ordered: number;
|
||||
customer_asked_for_fill: number;
|
||||
gallons_delivered: string;
|
||||
customer_filled: number;
|
||||
delivery_status: number;
|
||||
when_ordered: string;
|
||||
when_delivered: string;
|
||||
expected_delivery_date: string;
|
||||
automatic: number;
|
||||
oil_id: number;
|
||||
supplier_price: string;
|
||||
customer_price: string;
|
||||
customer_temperature: string;
|
||||
dispatcher_notes: string;
|
||||
prime: number;
|
||||
same_day: number;
|
||||
payment_type: number;
|
||||
payment_card_id: number;
|
||||
driver_employee_id: number;
|
||||
driver_first_name: string;
|
||||
driver_last_name: string;
|
||||
|
||||
}
|
||||
|
||||
export type customertype = {
|
||||
ok: boolean
|
||||
id: number;
|
||||
user_id: number;
|
||||
customer_first_name: string;
|
||||
customer_last_name: string;
|
||||
customer_town: string;
|
||||
customer_address: string;
|
||||
customer_state: number;
|
||||
customer_zip: string;
|
||||
customer_apt: string;
|
||||
customer_home_type: number;
|
||||
customer_phone_number: string;
|
||||
account_number: string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
export type pastdeliverytype = {
|
||||
ok: boolean
|
||||
id: number;
|
||||
customer_id: string;
|
||||
customer_name: string;
|
||||
customer_address: string;
|
||||
customer_town: string;
|
||||
customer_state: number;
|
||||
customer_zip: string;
|
||||
gallons_ordered: number;
|
||||
customer_asked_for_fill: number;
|
||||
gallons_delivered: string;
|
||||
customer_filled: number;
|
||||
delivery_status: number;
|
||||
when_ordered: string;
|
||||
when_delivered: string;
|
||||
expected_delivery_date: string;
|
||||
automatic: number;
|
||||
oil_id: number;
|
||||
supplier_price: string;
|
||||
customer_price: string;
|
||||
customer_temperature: string;
|
||||
dispatcher_notes: string;
|
||||
prime: number;
|
||||
same_day: number;
|
||||
payment_type: number;
|
||||
payment_card_id: number;
|
||||
driver_employee_id: number;
|
||||
driver_first_name: string;
|
||||
driver_last_name: string;
|
||||
}
|
||||
@@ -1,177 +1,22 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { PUBLIC_BASE_URL } from "$env/static/public";
|
||||
import type { company, oilprice } from '$lib/types/types'
|
||||
|
||||
export let company_data: company;
|
||||
export let oil_price_data: oilprice;
|
||||
|
||||
let price_of_oil: string = '';
|
||||
let company_name: string = '';
|
||||
let company_phone_number: string = '';
|
||||
|
||||
onMount(async () => {
|
||||
await fetch(PUBLIC_BASE_URL + "/info/price/today", {
|
||||
method: "get",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((result) => (oil_price_data = result));
|
||||
|
||||
if (oil_price_data["ok"] == true) {
|
||||
price_of_oil = oil_price_data["todays_price"];
|
||||
|
||||
}
|
||||
});
|
||||
onMount(async () => {
|
||||
await fetch(PUBLIC_BASE_URL + "/info/company", {
|
||||
method: "get",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((result) => (company_data = result));
|
||||
|
||||
if (company_data["ok"] == true) {
|
||||
company_name = company_data["company_name"];
|
||||
company_phone_number = company_data["company_phone_number"];
|
||||
}
|
||||
});
|
||||
import '../../app.postcss'; // Import Tailwind CSS
|
||||
</script>
|
||||
|
||||
<html lang="en">
|
||||
<div class="min-h-screen bg-white flex flex-col">
|
||||
<header class="navbar bg-primary text-primary-content shadow-lg">
|
||||
<div class="flex-1">
|
||||
<a href="/" class="btn btn-ghost normal-case text-xl">Heating Price Hero</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<head>
|
||||
<main class="flex-grow container mx-auto p-4">
|
||||
<slot />
|
||||
</main>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<meta name="description" content="Auburn Oil provides reliable heating oil delivery, expert HVAC service, and boiler maintenance to homes in Auburn, Worcester, Oxford, Sutton, and Webster. Experience comfort and peace of mind with our local service.">
|
||||
</head>
|
||||
<div class="grid grid-cols-12 bg-white overflow-hidden">
|
||||
<div class="col-span-12 md:col-span-3 text-3xl p-10 text-base-100 font-bold invisible md:visible h-0 md:h-auto">
|
||||
<div class="text-center pt-5">Call Today</div>
|
||||
<div class="text-center">{company_phone_number}</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-12 md:col-span-6 md:p-10 text-center font-bold ">
|
||||
<div class="md:flex md:justify-center pb-5 md:pb-0 gap-5">
|
||||
<a
|
||||
class="normal-case text-8xl text-primary"
|
||||
href="/"
|
||||
>
|
||||
Auburn
|
||||
</a>
|
||||
<a
|
||||
class="normal-case text-8xl text-primary"
|
||||
href="/"
|
||||
>
|
||||
Oil
|
||||
</a>
|
||||
</div>
|
||||
<a
|
||||
class="normal-case text-3xl text-primary "
|
||||
href="/">Oil thats good for your system</a
|
||||
>
|
||||
</div>
|
||||
|
||||
|
||||
<div
|
||||
class=" col-span-12 md:col-span-3 md:p-10 text-3xl text-base-100 font-bold"
|
||||
>
|
||||
<div class="text-center pt-5">Todays Price</div>
|
||||
<div class="text-center">${price_of_oil}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="navbar bg-primary">
|
||||
<div class="navbar-start">
|
||||
<div class="dropdown">
|
||||
<div tabindex="0" role="button" class="btn btn-ghost lg:hidden">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
><path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 6h16M4 12h8m-8 6h16"
|
||||
/></svg
|
||||
>
|
||||
</div>
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<ul
|
||||
tabindex="0"
|
||||
class="menu menu-sm dropdown-content mt-3 z-[1] p-2 shadow bg-white rounded-box w-52 font-bold text-blue-800 "
|
||||
>
|
||||
<li><a class="text-2xl py-2 hover:bg-base-100" href="/">Home</a></li>
|
||||
<li><a class="text-2xl py-2 hover:bg-base-100" href="/delivery">Oil Delivery</a></li>
|
||||
<li><a class="text-2xl py-2 hover:bg-base-100" href="/servicearea">Delivery Area</a></li>
|
||||
<li><a class="text-2xl py-2 hover:bg-base-100" href="/about">About Us</a></li>
|
||||
<li><a class="text-2xl py-2 hover:bg-base-100" href="/contact">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<a href="/" class="btn btn-ghost text-xl">AuburnOil</a>
|
||||
</div>
|
||||
<div class="navbar-center hidden lg:flex text-white">
|
||||
<ul class="menu menu-horizontal px-1 text-xl">
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/delivery">Oil Delivery</a></li>
|
||||
<li><a href="/servicearea">Delivery Area</a></li>
|
||||
<li><a href="/about">About Us</a></li>
|
||||
<li><a href="/contact">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="navbar-end"></div>
|
||||
<footer class="footer footer-center p-4 bg-base-300 text-base-content">
|
||||
<div>
|
||||
<p>Copyright © {new Date().getFullYear()} - All right reserved</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<body>
|
||||
<div class="body bg-white text-black">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
</body>
|
||||
<footer>
|
||||
<div class="grid grid-cols-12 bg-secondary py-10 w-full">
|
||||
<div
|
||||
class="col-span-12 md:col-span-4 text-center text-white text-bold text-6xl "
|
||||
>
|
||||
<div class="flex justify-center pt-5">
|
||||
<div class=" text-white px-1">Auburn</div>
|
||||
<div class=" text-white px-1">Oil</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="col-span-12 md:col-span-4 text-center text-bold text-xl text-white pb-10"
|
||||
>
|
||||
<div class="">{company_phone_number}</div>
|
||||
<div class="">Worcester Ma</div>
|
||||
<div class="">Mon - Fri 8:00 am - 5:00 pm</div>
|
||||
<div class="">Sat Closed | Sun Closed</div>
|
||||
</div>
|
||||
<div class="col-span-12 md:col-span-4 pb-10 text-center">
|
||||
<div class="flex-1"><a href="/">Home</a></div>
|
||||
<div class="flex-1"><a href="/delivery">Oil Delivery</a></div>
|
||||
<div class="flex-1"><a href="/servicearea">Delivery Area</a></div>
|
||||
<div class="flex-1"><a href="/about">About Us</a></div>
|
||||
<div class="flex-1"><a href="/contact">Contact</a></div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-12 h-auto bg-primary text-white w-full ">
|
||||
<div class=" mx-auto max-w-7xl p-5">
|
||||
<div class="text-xl font-bold text-center">
|
||||
© 2023 by Rocket Services LLC - Auburn, MA | All Rights Reserved
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</html>
|
||||
@@ -1,184 +1,74 @@
|
||||
<!-- src/routes/+page.svelte -->
|
||||
<script lang="ts">
|
||||
import "../../app.postcss";
|
||||
import { onMount } from "svelte";
|
||||
import { PUBLIC_BASE_URL } from "$env/static/public";
|
||||
import type { company, oilprice } from '$lib/types/types'
|
||||
import { newEnglandStates, mapViewBox } from '$lib/states';
|
||||
import { goto } from '$app/navigation';
|
||||
import { browser } from '$app/environment'; // To ensure SVG interactions only run client-side
|
||||
|
||||
export let company_data: company;
|
||||
export let oil_price_data: oilprice;
|
||||
|
||||
let hoveredState: string | null = null;
|
||||
|
||||
let price_of_oil: string = '';
|
||||
let company_name: string = '';
|
||||
let company_phone_number: string = '';
|
||||
|
||||
|
||||
onMount(async () => {
|
||||
await fetch(PUBLIC_BASE_URL + "/info/price/today", {
|
||||
method: "get",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((result) => (oil_price_data = result));
|
||||
|
||||
if (oil_price_data["ok"] == true) {
|
||||
price_of_oil = oil_price_data["todays_price"];
|
||||
function handleStateClick(id: string) {
|
||||
goto(`/${id}`);
|
||||
}
|
||||
});
|
||||
onMount(async () => {
|
||||
await fetch(PUBLIC_BASE_URL + "/info/company", {
|
||||
method: "get",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((result) => (company_data = result));
|
||||
|
||||
if (company_data["ok"] == true) {
|
||||
company_name = company_data["company_name"];
|
||||
company_phone_number = company_data["company_phone_number"];
|
||||
function handleMouseEnter(stateId: string) {
|
||||
if (browser) {
|
||||
hoveredState = stateId;
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseLeave() {
|
||||
if (browser) {
|
||||
hoveredState = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<title>Auburn Oil: Heating Oil Delivery Service in Southern Worcester County</title>
|
||||
<div class="bg-blue-900 text-white">
|
||||
<div class="bg-secondary px-10">
|
||||
<div class="max-w-7xl justify-center py-5 mx-auto font-bold text-white">
|
||||
<h1 class="text-center text-xl">Delivering Oil to Worcester County</h1>
|
||||
</div>
|
||||
|
||||
<div class="text-center mb-8">
|
||||
|
||||
<p class="text-lg">Click your state to find prices.</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mx-auto p-0 ">
|
||||
<img class="mx-auto p-0 m-0 overflow-hidden" src="/images/worc.png" alt="Auburn Massachusetts" />
|
||||
</div>
|
||||
|
||||
<div class="mx-auto p-10">
|
||||
<div class="mx-auto pb-5 text-5xl text-center">Order Now</div>
|
||||
<div class="mx-auto text-5xl text-center">
|
||||
{company_phone_number}
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-12 gap-5 px-5 text-center mt-10">
|
||||
<div class="col-span-12 font-bold text-4xl text-blue-400 mx-auto">
|
||||
Why call Auburn Oil?
|
||||
</div>
|
||||
<div class="col-span-12 lg:col-span-2"></div>
|
||||
<div class="col-span-12 lg:col-span-3 bg-base-100 p-10">
|
||||
<div class="text-4xl mb-3">Cheaper Prices</div>
|
||||
<div class="text-lg">
|
||||
No Middleman. No expensive bulk plants. Direct port to door for
|
||||
cheapest prices.
|
||||
<div class="flex justify-center items-center">
|
||||
{#if browser}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox={mapViewBox}
|
||||
class="w-full max-w-md h-auto border border-gray-300 rounded-lg shadow-md"
|
||||
aria-labelledby="mapTitle"
|
||||
role="img"
|
||||
>
|
||||
<title id="mapTitle">Interactive Map of New England States</title>
|
||||
{#each newEnglandStates as state}
|
||||
<path
|
||||
d={state.pathD}
|
||||
class={`stroke-black stroke-1 cursor-pointer transition-all duration-150 ease-in-out
|
||||
${hoveredState === state.id ? state.hoverFill : state.fill}`}
|
||||
on:click={() => handleStateClick(state.id)}
|
||||
on:mouseenter={() => handleMouseEnter(state.id)}
|
||||
on:mouseleave={handleMouseLeave}
|
||||
aria-label={state.id}
|
||||
tabindex="0"
|
||||
role="link"
|
||||
on:keydown={(e) => { if (e.key === 'Enter' || e.key === ' ') handleStateClick(state.id)}}
|
||||
>
|
||||
<title>{state.name}</title> <!-- Tooltip on hover -->
|
||||
</path>
|
||||
{/each}
|
||||
</svg>
|
||||
{:else}
|
||||
<div class="w-full max-w-2xl h-[500px] bg-gray-200 animate-pulse rounded-lg flex justify-center items-center">
|
||||
<p>Loading map...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-12 lg:col-span-3 bg-base-100 p-10">
|
||||
<div class="text-4xl mb-3">Phone Support</div>
|
||||
<div class="text-lg">
|
||||
Real live person on the phone when you call.
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-12 lg:col-span-3 bg-base-100 p-10">
|
||||
<div class="text-4xl mb-3">Top Quality Oil</div>
|
||||
<div class="text-lg">
|
||||
We dont cut our product with biodiesel. We use the best available
|
||||
oil for your heating system
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-12 lg:col-span-2"></div>
|
||||
<div class="col-span-12 lg:text-center text-center bg-orange-700">
|
||||
<div class="text-3xl ">
|
||||
We Offer Automatic Delivery
|
||||
</div>
|
||||
<div class="text-xl p-5">We will automatically fill your home and keep your family comfortable without worries
|
||||
about oil levels.
|
||||
</div>
|
||||
<div class="text-xl">Always get priority delivery status.</div>
|
||||
</div>
|
||||
<div class="col-span-6 text-lg text-center">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="h-auto">
|
||||
<div class="mx-auto p-5">
|
||||
<div class="grid grid-cols-12">
|
||||
<div class="col-span-12 py-5">
|
||||
<div
|
||||
class="font-bold text-5xl text-blue-400 max-w-7xl mx-auto text-center md:text-left"
|
||||
>
|
||||
Serving these communites
|
||||
</div>
|
||||
<div
|
||||
class="font-bold text-xl bg-blue-400 text-blue-800 h-10 mb-10"
|
||||
></div>
|
||||
</div>
|
||||
<div class="col-span-12 py-5">
|
||||
<div
|
||||
class="invisible md:visible h-0 md:h-auto flex gap-20 justify-center text-2xl"
|
||||
>
|
||||
<div >
|
||||
<div class="text-2xl">Auburn</div>
|
||||
<div class="text-2xl">Millbury</div>
|
||||
<div class="text-2xl">Sutton</div>
|
||||
<div class="text-2xl">Oxford</div>
|
||||
<div class="text-2xl">North Oxford</div>
|
||||
<div class="text-2xl">Webster</div>
|
||||
<div class="text-2xl">SouthBridge</div>
|
||||
<div class="text-2xl">Douglas</div>
|
||||
<div class="text-2xl">Shrewsbury</div>
|
||||
<div class="text-2xl">Grafton</div>
|
||||
</div>
|
||||
<div >
|
||||
<div class="text-2xl">Dudley</div>
|
||||
<div class="text-2xl">Sutton</div>
|
||||
<div class="text-2xl">Charlton</div>
|
||||
<div class="text-2xl">Leicester</div>
|
||||
<div class="text-2xl">Cherry Valley</div>
|
||||
<div class="text-2xl">Rochdale</div>
|
||||
<div class="text-2xl">Spencer</div>
|
||||
<div class="text-2xl">Sturbridge</div>
|
||||
<div class="text-2xl">Southbridge</div>
|
||||
<div class="text-2xl">Worcester</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="visible sm:visible md:invisible h-auto sm:h-auto md:h-0">
|
||||
<div class="text-center">
|
||||
<div class="text-2xl">Auburn</div>
|
||||
<div class="text-2xl">Millbury</div>
|
||||
<div class="text-2xl">Sutton</div>
|
||||
<div class="text-2xl">Oxford</div>
|
||||
<div class="text-2xl">North Oxford</div>
|
||||
<div class="text-2xl">Webster</div>
|
||||
<div class="text-2xl">Southbridge</div>
|
||||
<div class="text-2xl">Douglas</div>
|
||||
<div class="text-2xl">Shrewsbury</div>
|
||||
<div class="text-2xl">Grafton</div>
|
||||
<div class="text-2xl">Dudley</div>
|
||||
<div class="text-2xl">Charlton</div>
|
||||
<div class="text-2xl">Leicester</div>
|
||||
<div class="text-2xl">Cherry Valley</div>
|
||||
<div class="text-2xl">Rochdale</div>
|
||||
<div class="text-2xl">Spencer</div>
|
||||
<div class="text-2xl">Sutton</div>
|
||||
<div class="text-2xl">Sturbridge</div>
|
||||
<div class="text-2xl">Southbridge</div>
|
||||
<div class="text-2xl">Worcester</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-12 py-5">
|
||||
<div class="flex justify-center items-center ">
|
||||
<img class="" src="/images/area.png" alt="Worcester County oil delivery" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="mt-8 text-center">
|
||||
<h2 class="text-2xl font-semibold mb-4">States:</h2>
|
||||
<ul class="flex flex-wrap justify-center gap-4">
|
||||
{#each newEnglandStates as state}
|
||||
<li>
|
||||
<a href="/{state.id}" class="btn btn-outline btn-secondary">{state.name}</a>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
85
src/routes/(app)/[stateSlug]/+page.svelte
Executable file
@@ -0,0 +1,85 @@
|
||||
<!-- src/routes/[stateSlug]/+page.svelte -->
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { newEnglandStates, allCounties, type NewEnglandState } from '$lib/states'; // <--- Import type and counties
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
// The stateSlug from $page.params is guaranteed to be a string if this route matches
|
||||
// because [stateSlug] is a required parameter.
|
||||
const { stateSlug } = $page.params as { stateSlug: string }; // Type assertion for clarity
|
||||
|
||||
let stateData: NewEnglandState | undefined;
|
||||
let filteredCounties: any[] = [];
|
||||
let loading = false;
|
||||
let error: string | null = null;
|
||||
|
||||
onMount(async () => {
|
||||
stateData = newEnglandStates.find(s => s.id === stateSlug);
|
||||
if (stateData) {
|
||||
loading = true;
|
||||
try {
|
||||
const response = await fetch(`http://localhost:9552/state/${stateSlug.toUpperCase()}`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`API call failed with status ${response.status}`);
|
||||
}
|
||||
filteredCounties = await response.json();
|
||||
} catch (err) {
|
||||
error = err instanceof Error ? err.message : 'Failed to fetch counties';
|
||||
filteredCounties = [];
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{#if stateData}
|
||||
<div class="card lg:card-side bg-base-100 shadow-xl">
|
||||
<figure class=" ">
|
||||
<img
|
||||
src={stateData.image}
|
||||
alt="Map or notable feature of {stateData.id}"
|
||||
class="object-cover"
|
||||
/>
|
||||
</figure>
|
||||
<div class="card-body lg:w-1/2">
|
||||
<h1 class="card-title text-4xl">{stateData.name}</h1>
|
||||
<p>This is the page for {stateData.name}. Here you can add more specific information about this wonderful state!</p>
|
||||
<p>The URL for this page is <code class="bg-base-300 p-1 rounded">/{stateData.id}</code> which is {stateData.id.length} characters long.</p>
|
||||
<div class="mt-4">
|
||||
<h2 class="text-xl font-semibold mb-2">Counties:</h2>
|
||||
{#if loading}
|
||||
<p>Loading counties...</p>
|
||||
{:else if error}
|
||||
<p class="text-error">Error: {error}</p>
|
||||
{:else}
|
||||
<ul class="list-disc pl-5">
|
||||
{#each filteredCounties as county}
|
||||
<li>
|
||||
<a href="http://localhost:9551/{stateSlug.toUpperCase()}/{county.id}" class="text-blue-600 hover:underline">{county.name}</a>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="card-actions justify-end mt-4">
|
||||
<a href="/" class="btn btn-primary">Back to Map</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{:else if !stateData && stateSlug} <!-- Check if stateData is still undefined after onMount attempted to find it -->
|
||||
<div class="text-center py-10">
|
||||
<h1 class="text-3xl font-bold text-error">State Not Found</h1>
|
||||
<p class="mt-4">Could not find information for a state with ID: "{stateSlug}".</p>
|
||||
<a href="/" class="btn btn-primary mt-6">Go Back to Map</a>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
figure img {
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
44
src/routes/(app)/[stateSlug]/[countySlug]/+page.svelte
Normal file
@@ -0,0 +1,44 @@
|
||||
<!-- src/routes/(app)/[stateSlug]/[countySlug]/+page.svelte -->
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
const { stateSlug, countySlug } = $page.params as { stateSlug: string; countySlug: string };
|
||||
let countyData: { id: number; name: string; state: string } | null = null;
|
||||
let loading = true;
|
||||
let error: string | null = null;
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
// Ensure API URL matches the Docker port forwarding for API (9552)
|
||||
const response = await fetch(`http://localhost:9552/state/${stateSlug.toUpperCase()}/${countySlug}`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch county data: ${response.statusText}`);
|
||||
}
|
||||
countyData = await response.json();
|
||||
} catch (err) {
|
||||
error = err instanceof Error ? err.message : 'An error occurred while fetching county data.';
|
||||
countyData = null;
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
});
|
||||
</script>3
|
||||
|
||||
{#if loading}
|
||||
<div class="text-center py-10">
|
||||
<p>Loading county data...</p>
|
||||
</div>
|
||||
{:else if countyData}
|
||||
<div class="text-center py-10">
|
||||
<h1 class="text-3xl font-bold">{countyData.name}</h1>
|
||||
<p class="text-xl mt-4">County ID: {countyData.id}</p>
|
||||
<a href="/{stateSlug}" class="btn btn-primary mt-6">Back to State</a>
|
||||
</div>
|
||||
{:else if error}
|
||||
<div class="text-center py-10">
|
||||
<h1 class="text-3xl font-bold text-error">County Not Found</h1>
|
||||
<p class="mt-4">{error}</p>
|
||||
<a href="/" class="btn btn-primary mt-6">Go Back to Map</a>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -1,72 +0,0 @@
|
||||
<div class="bg-secondary px-10">
|
||||
<div
|
||||
class="max-w-7xl justify-center py-5 mx-auto font-bold text-white"
|
||||
>
|
||||
<h1>About Us</h1>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="max-w-7xl mx-auto px-10">
|
||||
<div class="grid grid-cols-12 max-w-7xl gap-5">
|
||||
<div class="col-span-12 text-2xl text-bold"></div>
|
||||
<div class="col-span-12 md:col-span-6 mb-20">
|
||||
<div class="col-span-12 mb-5 font-bold text-xl text-primary">
|
||||
Our Oil Wont Ruin your heating system!
|
||||
</div>
|
||||
<div class="col-span-12 text-lg">
|
||||
After 20 years delivering for other companies in Worcester. Our family
|
||||
decided it was time to start our own small business. We have the
|
||||
experience to ensure your family stays warm!
|
||||
</div>
|
||||
<div class="col-span-12 mb-5 text-2xl font-bold mt-10 text-primary">
|
||||
The best oil in your Tank
|
||||
</div>
|
||||
<div class="col-span-12 mb-10">
|
||||
<ul>
|
||||
<div class="flex gap-5">
|
||||
<img class=" p-0 m-0 h-10 w-5" src="/images/flame.png" alt="" />
|
||||
<li class=" font-bold text-error">2-5% biodiesel (B2–B5) is Bioheat® fuel (Our Oil)</li>
|
||||
</div>
|
||||
<div class="flex gap-5">
|
||||
<img class=" p-0 m-0 h-10 w-5" src="/images/flame.png" alt="" />
|
||||
<li class=" font-bold">
|
||||
5-20% biodiesel (B5–B20) is Bioheat Plus® fuel
|
||||
</li>
|
||||
</div>
|
||||
<div class="flex gap-5">
|
||||
<img class=" p-0 m-0 h-10 w-5" src="/images/flame.png" alt="" />
|
||||
<li class=" font-bold">
|
||||
20% biodiesel and above (B20+) is Bioheat Super Plus®
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-span-12 mb-5 font-bold text-xl text-primary">
|
||||
Symptoms your oil company is selling you bad oil
|
||||
</div>
|
||||
|
||||
<div class="col-span-12 mb-10">
|
||||
<ul class="text-lg">
|
||||
<li>- System needs filters frequently</li>
|
||||
<li>- Furnace has bad flame and doesnt produce high heat</li>
|
||||
<li>- System is clogged</li>
|
||||
<li>- Tank goes bad all of a sudden!</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-span-12 mb-5 font-bold text-xl">
|
||||
See the slime? Imagine that all inside your tank and equipment!
|
||||
</div>
|
||||
<div class="col-span-12 mb-5 font-bold text-xl text-center">
|
||||
Thats a bio filled system :(
|
||||
</div>
|
||||
|
||||
<div class="col-span-12">
|
||||
<img class="w-full p-0 m-0" src="/images/slimefilter.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-12 md:col-span-6">
|
||||
<img class="w-full p-0 m-0" src="/images/oildelivery.jpg" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,91 +0,0 @@
|
||||
<script lang="ts">
|
||||
import "../../../app.postcss";
|
||||
import { onMount } from "svelte";
|
||||
import { PUBLIC_BASE_URL } from "$env/static/public";
|
||||
import type { company, oilprice } from "$lib/types/types";
|
||||
|
||||
export let company_data: company;
|
||||
export let oil_price_data: oilprice;
|
||||
|
||||
let price_of_oil: string = "";
|
||||
let company_name: string = "";
|
||||
let company_phone_number: string = "";
|
||||
|
||||
onMount(async () => {
|
||||
await fetch(PUBLIC_BASE_URL + "/info/price/today", {
|
||||
method: "get",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((result) => (oil_price_data = result));
|
||||
|
||||
if (oil_price_data["ok"] == true) {
|
||||
price_of_oil = oil_price_data["todays_price"];
|
||||
}
|
||||
});
|
||||
onMount(async () => {
|
||||
await fetch(PUBLIC_BASE_URL + "/info/company", {
|
||||
method: "get",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((result) => (company_data = result));
|
||||
|
||||
if (company_data["ok"] == true) {
|
||||
company_name = company_data["company_name"];
|
||||
company_phone_number = company_data["company_phone_number"];
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="bg-secondary px-10">
|
||||
<div
|
||||
class="max-w-7xl justify-center py-5 mx-auto font-bold text-white"
|
||||
>
|
||||
<h1>Contact</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="max-w-7xl mx-auto px-10">
|
||||
<div class="grid grid-cols-2 gap-5">
|
||||
<div class="col-span-2 md:col-span-1">
|
||||
<div class="text-2xl font-bold text-primary">Contact Us</div>
|
||||
<div class="mb-20 text-xl">Phone: {company_phone_number}</div>
|
||||
|
||||
<div class="mb-10">
|
||||
<div class="font-bold text-2xl text-primary max-w-7xl mx-auto">
|
||||
Business Hours Summer
|
||||
</div>
|
||||
<div class="font-bold text-xl bg-primary text-white h-2 mb-2"></div>
|
||||
<div class="text-xl">Monday: 8:00 a.m. – 5:00 p.m.</div>
|
||||
<div class="text-xl">Tuesday: 8:30 a.m. – 5:00 p.m.</div>
|
||||
<div class="text-xl">Wednesday: 8:30 a.m. – 5:00 p.m.</div>
|
||||
<div class="text-xl">Thursday: 8:00 a.m. – 5:00 p.m.</div>
|
||||
<div class="text-xl">Friday: 8:00 a.m. – 3:00 p.m.</div>
|
||||
<div class="text-xl">Saturday: Closed</div>
|
||||
<div class="text-xl">Sunday: Closed</div>
|
||||
</div>
|
||||
<div class="">
|
||||
<div class="font-bold text-2xl text-primary max-w-7xl mx-auto">
|
||||
Business Hours Winter
|
||||
</div>
|
||||
<div class="font-bold text-xl bg-primary text-white h-2 mb-2"></div>
|
||||
<div class="text-xl">Monday: 8:00 a.m. – 5:00 p.m.</div>
|
||||
<div class="text-xl">Tuesday: 8:30 a.m. – 5:00 p.m.</div>
|
||||
<div class="text-xl">Wednesday: 8:30 a.m. – 5:00 p.m.</div>
|
||||
<div class="text-xl">Thursday: 8:00 a.m. – 5:00 p.m.</div>
|
||||
<div class="text-xl">Friday: 8:00 a.m. – 5:00 p.m.</div>
|
||||
<div class="text-xl">Saturday: 8:00 a.m. – 1:00 p.m.</div>
|
||||
<div class="text-xl">Sunday: Closed</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-2 md:col-span-1">
|
||||
<img class="w-auto" src="/images/contact.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,121 +0,0 @@
|
||||
<script lang='ts'>
|
||||
import "../../../app.postcss";
|
||||
import { onMount } from "svelte";
|
||||
import { PUBLIC_BASE_URL } from "$env/static/public";
|
||||
import type { company } from '$lib/types/types'
|
||||
|
||||
export let company_data: company;
|
||||
|
||||
|
||||
let company_name: string = '';
|
||||
let tel_number: string = '';
|
||||
|
||||
onMount(async () => {
|
||||
await fetch(PUBLIC_BASE_URL + "/info/company", {
|
||||
method: "get",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((result) => (company_data = result));
|
||||
|
||||
if (company_data["ok"] == true) {
|
||||
company_name = company_data["company_name"];
|
||||
tel_number = company_data["company_phone_number"];
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<div class="bg-secondary px-10">
|
||||
<div
|
||||
class="max-w-7xl justify-center py-5 mx-auto font-bold text-white"
|
||||
>
|
||||
<h1>Heating Oil Delivery</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="max-w-7xl mx-auto px-10">
|
||||
<div class="grid grid-cols-12 max-w-7xl">
|
||||
<div class="col-span-12 lg:col-span-6">
|
||||
<div class="grid grid-cols-12">
|
||||
|
||||
<div class="col-span-12 font-bold text-2xl my-10">
|
||||
We know it can be tough to order oil. We make it simple!
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-span-12 font-bold text-xl text-primary">
|
||||
Worcester County
|
||||
</div>
|
||||
<div class="col-span-12 text-lg">
|
||||
<ul>100 Gallon Minimum to Worcester County</ul>
|
||||
<ul>Prime - 25$</ul>
|
||||
<ul>Same Day - 150$</ul>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-span-12 font-bold mt-10 text-xl text-primary">
|
||||
Payments Methods
|
||||
</div>
|
||||
<div class="col-span-12 text-lg">
|
||||
<ul>Cash on Delivery (C.O.D)</ul>
|
||||
<ul>Credit Card</ul>
|
||||
<ul>Money Order</ul>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-span-12 mb-10">
|
||||
<ul>
|
||||
<div class="col-span-12 font-bold mt-10 text-xl text-primary">
|
||||
How to Order Oil
|
||||
</div>
|
||||
<div class="flex gap-5">
|
||||
|
||||
<li class=" font-bold">
|
||||
1.) Call {tel_number} to place an order.
|
||||
</li>
|
||||
</div>
|
||||
<div class="flex gap-5">
|
||||
|
||||
<li class=" font-bold">
|
||||
2.) Give your name, address, fill location, and phone number.
|
||||
</li>
|
||||
</div>
|
||||
<div class="flex gap-5">
|
||||
<li class=" font-bold">
|
||||
3.) Decide if you want a fill or specific gallons
|
||||
</li>
|
||||
</div>
|
||||
<div class="flex gap-5">
|
||||
<li class=" font-bold">
|
||||
4.) Pay with Credit Card or pay the driver cash
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-span-12 mx-auto py-10">
|
||||
<img class=" h-20 w-auto" src="/images/creditcards.png" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-12 md:col-span-6">
|
||||
<div class="col-span-12">
|
||||
<img alt="" class="w-full p-0 m-0" src="/images/worc.jpg" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-12 mb-10
|
||||
text-bold bg-primary text-white mt-10 text-5xl text-bold
|
||||
p-5 text-center">
|
||||
Call Today {tel_number}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
111
src/routes/(app)/login/+page.svelte
Executable file
@@ -0,0 +1,111 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import type { LoginRequest } from '$lib/types/types';
|
||||
|
||||
let username = '';
|
||||
let password = '';
|
||||
let errorMessage = '';
|
||||
let isLoading = false;
|
||||
|
||||
async function handleSubmit() {
|
||||
const loginData: LoginRequest = {
|
||||
username,
|
||||
password
|
||||
};
|
||||
|
||||
isLoading = true;
|
||||
errorMessage = '';
|
||||
|
||||
try {
|
||||
const response = await fetch('/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(loginData)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
errorMessage = errorData.error || 'Login failed';
|
||||
} else {
|
||||
const data = await response.json();
|
||||
// Assuming the backend returns a token or some success indicator
|
||||
// Redirect to home page or dashboard after successful login
|
||||
goto('/');
|
||||
}
|
||||
} catch (err) {
|
||||
errorMessage = 'An error occurred. Please try again.';
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex min-h-screen flex-col items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div class="w-full max-w-md space-y-8">
|
||||
<div>
|
||||
<h2 class="mt-6 text-center text-3xl font-bold tracking-tight text-gray-900">Sign in to your account</h2>
|
||||
</div>
|
||||
|
||||
{#if errorMessage}
|
||||
<div class="rounded-md bg-red-50 p-4">
|
||||
<div class="flex">
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-red-800">{errorMessage}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<form class="mt-8 space-y-6" on:submit|preventDefault={handleSubmit}>
|
||||
<input type="hidden" name="remember" value="true" />
|
||||
<div class="-space-y-px rounded-md shadow-sm">
|
||||
<div>
|
||||
<label for="username" class="sr-only">Username</label>
|
||||
<input
|
||||
id="username"
|
||||
name="username"
|
||||
type="text"
|
||||
autocomplete="username"
|
||||
required
|
||||
bind:value={username}
|
||||
class="relative block w-full rounded-t-md border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:z-10 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
||||
placeholder="Username"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="password" class="sr-only">Password</label>
|
||||
<input
|
||||
id="password"
|
||||
name="password"
|
||||
type="password"
|
||||
autocomplete="current-password"
|
||||
required
|
||||
bind:value={password}
|
||||
class="relative block w-full rounded-b-md border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:z-10 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
||||
placeholder="Password"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
class="group relative flex w-full justify-center rounded-md bg-indigo-600 py-2 px-3 text-sm font-semibold text-white hover:bg-indigo-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
|
||||
>
|
||||
{#if isLoading}
|
||||
<svg class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
Signing in...
|
||||
{:else}
|
||||
Sign in
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
144
src/routes/(app)/register/+page.svelte
Executable file
@@ -0,0 +1,144 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import type { RegisterRequest } from '$lib/types/types';
|
||||
|
||||
let email = '';
|
||||
let username = '';
|
||||
let password = '';
|
||||
let confirmPassword = '';
|
||||
let errorMessage = '';
|
||||
let isLoading = false;
|
||||
|
||||
async function handleSubmit() {
|
||||
if (password !== confirmPassword) {
|
||||
errorMessage = 'Passwords do not match';
|
||||
return;
|
||||
}
|
||||
|
||||
const registerData: RegisterRequest = {
|
||||
email,
|
||||
username,
|
||||
password
|
||||
};
|
||||
|
||||
isLoading = true;
|
||||
errorMessage = '';
|
||||
|
||||
try {
|
||||
const response = await fetch('/register', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(registerData)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
errorMessage = errorData.error || 'Registration failed';
|
||||
} else {
|
||||
// Redirect to login or home page after successful registration
|
||||
goto('/login');
|
||||
}
|
||||
} catch (err) {
|
||||
errorMessage = 'An error occurred. Please try again.';
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex min-h-screen flex-col items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div class="w-full max-w-md space-y-8">
|
||||
<div>
|
||||
<h2 class="mt-6 text-center text-3xl font-bold tracking-tight text-gray-900">Create your account</h2>
|
||||
</div>
|
||||
|
||||
{#if errorMessage}
|
||||
<div class="rounded-md bg-red-50 p-4">
|
||||
<div class="flex">
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-red-800">{errorMessage}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<form class="mt-8 space-y-6" on:submit|preventDefault={handleSubmit}>
|
||||
<input type="hidden" name="remember" value="true" />
|
||||
<div class="-space-y-px rounded-md shadow-sm">
|
||||
<div>
|
||||
<label for="email-address" class="sr-only">Email address</label>
|
||||
<input
|
||||
id="email-address"
|
||||
name="email"
|
||||
type="email"
|
||||
autocomplete="email"
|
||||
required
|
||||
bind:value={email}
|
||||
class="relative block w-full rounded-t-md border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:z-10 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
||||
placeholder="Email address"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="username" class="sr-only">Username</label>
|
||||
<input
|
||||
id="username"
|
||||
name="username"
|
||||
type="text"
|
||||
autocomplete="username"
|
||||
required
|
||||
bind:value={username}
|
||||
class="relative block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:z-10 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
||||
placeholder="Username"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="password" class="sr-only">Password</label>
|
||||
<input
|
||||
id="password"
|
||||
name="password"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
required
|
||||
bind:value={password}
|
||||
class="relative block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:z-10 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
||||
placeholder="Password"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="confirm-password" class="sr-only">Confirm Password</label>
|
||||
<input
|
||||
id="confirm-password"
|
||||
name="confirm-password"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
required
|
||||
bind:value={confirmPassword}
|
||||
class="relative block w-full rounded-b-md border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:z-10 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
||||
placeholder="Confirm Password"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
class="group relative flex w-full justify-center rounded-md bg-indigo-600 py-2 px-3 text-sm font-semibold text-white hover:bg-indigo-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
|
||||
>
|
||||
{#if isLoading}
|
||||
<svg class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
Registering...
|
||||
{:else}
|
||||
Register
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,79 +0,0 @@
|
||||
<title>Auburn Oil: Heating Oil Delivery Service in Southern Worcester County</title>
|
||||
|
||||
<div class="bg-secondary px-10">
|
||||
<div class="max-w-7xl justify-center py-5 mx-auto font-bold text-white">
|
||||
<h1>Delivery Area</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="h-auto">
|
||||
<div class="mx-auto p-5">
|
||||
<div class="grid grid-cols-12 ">
|
||||
<div class="col-span-12 py-5 ">
|
||||
<div class="font-bold text-secondary mx-auto text-center md:text-left">
|
||||
<h3>Serving these communites</h3>
|
||||
</div>
|
||||
<div class="font-bold text-xl bg-secondary text-primary h-10 mb-10">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-12 py-5 ">
|
||||
<div class="invisible md:visible h-0 md:h-auto flex gap-20 justify-center text-3xl">
|
||||
<div >
|
||||
<div class="text-2xl">Auburn</div>
|
||||
<div class="text-2xl">Millbury</div>
|
||||
<div class="text-2xl">Sutton</div>
|
||||
<div class="text-2xl">Oxford</div>
|
||||
<div class="text-2xl">North Oxford</div>
|
||||
<div class="text-2xl">Webster</div>
|
||||
<div class="text-2xl">Southbridge</div>
|
||||
<div class="text-2xl">Douglas</div>
|
||||
<div class="text-2xl">Shrewsbury</div>
|
||||
<div class="text-2xl">Grafton</div>
|
||||
</div>
|
||||
<div >
|
||||
<div class="text-2xl">Dudley</div>
|
||||
<div class="text-2xl">Sutton</div>
|
||||
<div class="text-2xl">Charlton</div>
|
||||
<div class="text-2xl">Leicester</div>
|
||||
<div class="text-2xl">Cherry Valley</div>
|
||||
<div class="text-2xl">Rochdale</div>
|
||||
<div class="text-2xl">Spencer</div>
|
||||
<div class="text-2xl">Sturbridge</div>
|
||||
<div class="text-2xl">Southbridge</div>
|
||||
<div class="text-2xl">Worcester</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="visible sm:visible md:invisible h-auto sm:h-auto md:h-0">
|
||||
<div class="text-center">
|
||||
<div class="text-2xl">Auburn</div>
|
||||
<div class="text-2xl">Millbury</div>
|
||||
<div class="text-2xl">Sutton</div>
|
||||
<div class="text-2xl">Oxford</div>
|
||||
<div class="text-2xl">North Oxford</div>
|
||||
<div class="text-2xl">Webster</div>
|
||||
<div class="text-2xl">Southbridge</div>
|
||||
<div class="text-2xl">Douglas</div>
|
||||
<div class="text-2xl">Shrewsbury</div>
|
||||
<div class="text-2xl">Grafton</div>
|
||||
<div class="text-2xl">Dudley</div>
|
||||
<div class="text-2xl">Charlton</div>
|
||||
<div class="text-2xl">Leicester</div>
|
||||
<div class="text-2xl">Cherry Valley</div>
|
||||
<div class="text-2xl">Rochdale</div>
|
||||
<div class="text-2xl">Spencer</div>
|
||||
<div class="text-2xl">Sutton</div>
|
||||
<div class="text-2xl">Sturbridge</div>
|
||||
<div class="text-2xl">Southbridge</div>
|
||||
<div class="text-2xl">Worcester</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-12 py-5 ">
|
||||
<div class="flex justify-center items-center md:h-auto">
|
||||
<img class="" src="/images/area.png" alt="Worcester County oil delivery">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
9
static/fonts.css
Executable file
@@ -0,0 +1,9 @@
|
||||
@font-face {
|
||||
font-family: 'EnterS';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: url('/fonts/entsans.tff'); /* IE9 Compat Modes */
|
||||
src: local(''), url('/fonts/entsans.ttf') format('truetype'),
|
||||
/* Modern Browsers */ url('/fonts/entsans.ttf') format('truetype'),
|
||||
|
||||
}
|
||||
|
Before Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 425 KiB |
|
Before Width: | Height: | Size: 1.5 MiB |
|
Before Width: | Height: | Size: 2.8 MiB |
|
Before Width: | Height: | Size: 1.1 MiB |
0
static/robots.txt
Normal file → Executable file
@@ -1,5 +1,5 @@
|
||||
import adapter from "@sveltejs/adapter-node";
|
||||
import { vitePreprocess } from "@sveltejs/kit/vite";
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
|
||||