Skip to content

Commit

Permalink
Upload file js (codeforboston#163)
Browse files Browse the repository at this point in the history
* Add file field to EnergyUseHistory

Co-authored-by: Camden Blatchly <[email protected]>
Co-authored-by: hectorbenitez19 <[email protected]>

* fix typo on livingArea (wrongly livingSpace) to allow submitting, trial of Pyodide, commented

Co-authored-by: Hector Benitez <[email protected]>
Co-authored-by: plocket <[email protected]>
Co-authored-by: Steve Breit <[email protected]>
Co-authored-by: thatoldplatitude <[email protected]>

---------

Co-authored-by: plocket <[email protected]>
Co-authored-by: Camden Blatchly <[email protected]>
Co-authored-by: hectorbenitez19 <[email protected]>
Co-authored-by: plocket <[email protected]>
Co-authored-by: Steve Breit <[email protected]>
Co-authored-by: thatoldplatitude <[email protected]>
  • Loading branch information
7 people authored Apr 23, 2024
1 parent 793cacc commit 8e8a939
Show file tree
Hide file tree
Showing 8 changed files with 367 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Button } from '#/app/components/ui/button.tsx'

import { AnalysisHeader } from './AnalysisHeader.tsx'
import { EnergyUseHistoryChart } from './EnergyUseHistoryChart.tsx'
import { Upload } from 'lucide-react'


// type EnergyUseProps = {fields: any};
Expand All @@ -20,10 +21,44 @@ export function EnergyUseHistory() {
<div>
<h2 className={`${titleClass}`}>Energy Use History</h2>
<div>
<Button type="submit">Upload</Button>
<input
id="energy_use_upload"
aria-label="Upload your energy billing company's bill."
onChange={event => {
const file = event.target.files?.[0]
if (file) {
// const reader = new FileReader()
// reader.onloadend = async (event) => {
// console.log('reader.result', reader.result)
// }
// reader.readAsText(file)
} else {
// setPreviewImage(null)
}
console.log('Boom!')
}}
name="energy_use_upload"
type="file"
accept="text/csv"
/>
<Button type="submit"> <Upload className="h-4 w-4 mr-2" /> Upload</Button>
</div>
<AnalysisHeader />
<EnergyUseHistoryChart />
</div>
)
}



// const file = event.target.files?.[0]

// if (file) {
// const reader = new FileReader()
// reader.onloadend = () => {
// setPreviewImage(reader.result as string)
// }
// reader.readAsDataURL(file)
// } else {
// setPreviewImage(null)
// }
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@ export function HomeInformation(props: HomeInformationProps) {

<div className="mt-4 flex space-x-2">
<div>
<Input name={props.fields.livingSpace.name} id="livingArea" type="number" />
<Input name={props.fields.livingArea.name} id="livingArea" type="number" />
<div className="min-h-[32px] px-4 pb-3 pt-1">
<ErrorList
id={props.fields.livingSpace.errorId}
errors={props.fields.livingSpace.errors}
id={props.fields.livingArea.errorId}
errors={props.fields.livingArea.errors}
/>
</div>
<p className={`${descriptiveClass}`}>
Expand Down
4 changes: 2 additions & 2 deletions heat-stack/app/routes/_heat+/Inputs1.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const addressMaxLength = 100
const HomeInformationSchema = z.object({
name: z.string().min(1).max(nameMaxLength),
address: z.string().min(1).max(addressMaxLength),
livingSpace: z.number().min(1),
livingArea: z.number().min(1),
})

export async function action({ request, params }: ActionFunctionArgs) {
Expand Down Expand Up @@ -56,7 +56,7 @@ export async function action({ request, params }: ActionFunctionArgs) {
// - [ ] Build form #2 and #3
// - [ ] Form errors (if we think of a use case - 2 fields conflicting...)

const { name, address, livingSpace } = submission.value
const { name, address, livingArea } = submission.value

// await updateNote({ id: params.noteId, title, content })

Expand Down
99 changes: 98 additions & 1 deletion heat-stack/app/routes/_heat+/single.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { invariantResponse } from '@epic-web/invariant'
import { json, ActionFunctionArgs } from '@remix-run/node'
import { Form, redirect, useActionData } from '@remix-run/react'
import { z } from 'zod'
import GeocodeUtil from "#app/utils/GeocodeUtil.js";
import WeatherUtil from "#app/utils/WeatherUtil.js";
import PyodideUtil from "#app/utils/pyodide.util.js";

// TODO NEXT WEEK
// - [x] Server side error checking/handling
Expand All @@ -32,6 +35,7 @@ import { HomeInformation } from '../../components/ui/heat/CaseSummaryComponents/
import HeatLoadAnalysis from './heatloadanalysis.tsx'
import { Button } from '#/app/components/ui/button.tsx'


const nameMaxLength = 50
const addressMaxLength = 100

Expand Down Expand Up @@ -69,12 +73,15 @@ export async function action({ request, params }: ActionFunctionArgs) {
// Checks if url has a homeId parameter, throws 400 if not there
// invariantResponse(params.homeId, 'homeId param is required')

console.log("action started")

const formData = await request.formData()
const submission = parseWithZod(formData, {
schema: Schema,
})

if (submission.status !== 'success') {
console.error("submission failed",submission)
return submission.reply()
// submission.reply({
// // You can also pass additional error to the `reply` method
Expand All @@ -97,10 +104,99 @@ export async function action({ request, params }: ActionFunctionArgs) {
designTemperatureOverride } = submission.value

// await updateNote({ id: params.noteId, title, content })
//code snippet from - https://github.com/epicweb-dev/web-forms/blob/2c10993e4acffe3dd9ad7b9cb0cdf89ce8d46ecf/exercises/04.file-upload/01.solution.multi-part/app/routes/users%2B/%24username_%2B/notes.%24noteId_.edit.tsx#L180

// const formData = await parseMultipartFormData(
// request,
// createMemoryUploadHandler({ maxPartSize: MAX_UPLOAD_SIZE }),
// )

console.log("loading PU/PM/GU/WU");

// CONSOLE: loading PU/PM/GU/WU
// Error: No known package with name 'pydantic_core'
// Error: No known package with name 'pydantic_core'
// at addPackageToLoad (/workspaces/home-energy-analysis-tool/heat-stack/public/pyodide-env/pyodide.asm.js:9:109097)
// at recursiveDependencies (/workspaces/home-energy-analysis-tool/heat-stack/public/pyodide-env/pyodide.asm.js:9:109370)
// at loadPackage (/workspaces/home-energy-analysis-tool/heat-stack/public/pyodide-env/pyodide.asm.js:9:111435)
// at initializePackageIndex (/workspaces/home-energy-analysis-tool/heat-stack/public/pyodide-env/pyodide.asm.js:9:108508)

// const PU = PyodideUtil.getInstance();
// const PM = await PU.getPyodideModule();
const GU = new GeocodeUtil();
const WU = new WeatherUtil();
// console.log("loaded PU/PM/GU/WU");

/**
*
* @param longitude
* @param latitude
* @param start_date
* @param end_date
* @returns {SI,TIWD,BI} Summary input: hardcoded data.TIWD: TemperatureInput: WeatherData from calling open meto API
* Billing input: hardcoded data
*
* Function just to generate test data. inputs come from the values entered in from HomeInformation component
*/
async function genny(longitude: number, latitude: number, start_date: string, end_date: string) {
// SI = new SummaryInput(6666,"GAS",80,67,null,null,60);
// was living_area: number, fuel_type: FuelType, heating_system_efficiency: number, thermostat_set_point: number, setback_temperature: number | null, setback_hours_per_day: number | null, design_temperature: number

type SchemaZodFromFormType = z.infer<typeof Schema>;



const oldSummaryInput = {
living_area: 6666,
fuel_type: "GAS",
heating_system_efficiency: 80,
thermostat_set_point: 67,
setback_temperature: null,
setback_hours_per_day: null,
design_temperature: 60,
};

const SI: SchemaZodFromFormType = Schema.parse({
livingArea: oldSummaryInput.living_area,
address: '123 Main St', // Provide a valid address
name: 'My Home', // Provide a valid name
fuelType: oldSummaryInput.fuel_type === 'GAS' ? 'Natural Gas' : oldSummaryInput.fuel_type,
heatingSystemEfficiency: oldSummaryInput.heating_system_efficiency,
thermostatSetPoint: oldSummaryInput.thermostat_set_point,
setbackTemperature: oldSummaryInput.setback_temperature,
setbackHoursPerDay: oldSummaryInput.setback_hours_per_day,
designTemperatureOverride: oldSummaryInput.design_temperature,
});

console.log("SI", SI)


// const TIWD: TemperatureInput = await WU.getThatWeathaData(longitude, latitude, start_date, end_date);
const TIWD = await WU.getThatWeathaData(longitude, latitude, start_date, end_date);
const BI = [{
period_start_date: new Date("2023-12-30"),//new Date("2023-12-30"),
period_end_date: new Date("2024-01-06"),
usage:100,
inclusion_override: null
}];
return {SI, TIWD, BI};
}


let { x, y } = await GU.getLL(address);
console.log("geocoded", x,y)

return redirect(`/inputs1`)
let { SI, TIWD, BI } = await genny(x,y,"2024-01-01","2024-01-03")

// PU.runit(SI,null,TIWD,JSON.stringify(BI));
// CSV entrypoint parse_gas_bill(data: str, company: NaturalGasCompany)
// Main form entrypoint

return redirect(`/single`)
}



export default function Inputs() {
const lastResult = useActionData<typeof action>()
const [form, fields] = useForm({
Expand All @@ -119,6 +215,7 @@ export default function Inputs() {
method="post"
onSubmit={form.onSubmit}
action="/single"
encType="multipart/form-data"
>
<HomeInformation fields={fields} />
<CurrentHeatingSystem fields={fields} />
Expand Down
29 changes: 29 additions & 0 deletions heat-stack/app/utils/GeocodeUtil.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const BASE_URL = "https://geocoding.geo.census.gov";
const ADDRESS_ENDPOINT = "/geocoder/locations/address";
const params = new URLSearchParams();

class GeocodeUtil {

/**
*
* @param {*} street
* @param {*} city
* @param {*} state
* @returns x,y {x,y} lon/lat. If the given address was valid. I've implemented 0 handling here.
* This is the happiest of paths, with hardcoded values also...
*/
async getLL(address) {
params.append("onelineaddress",address);
params.append("format","json");
params.append("benchmark",2020);

let url = new URL(BASE_URL+ADDRESS_ENDPOINT+"?"+params.toString());
let rezzy = await fetch(url);
let jrez = await rezzy.json();
let coordz = jrez.result.addressMatches[0].coordinates;
console.log(coordz);
return coordz;
}
}

export default GeocodeUtil;
31 changes: 31 additions & 0 deletions heat-stack/app/utils/WeatherUtil.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { time } from "console";

const BASE_URL = "https://archive-api.open-meteo.com";
const WHATEVER_PATH = "/v1/archive";
const params = new URLSearchParams();

class WeatherUtil {

async getThatWeathaData(longitude,latitude,startDate, endDate) {
params.append("latitude",latitude);
params.append("longitude",longitude);
params.append("daily","temperature_2m_max");
params.append("timezone","America/New_York");
params.append("start_date",startDate);
params.append("end_date",endDate);
params.append("temperature_unit","fahrenheit");

let url = new URL(BASE_URL+WHATEVER_PATH+"?"+params.toString());
let rezzy = await fetch(url);
let jrez = await rezzy.json();
let dates = [];
jrez.daily.time.forEach(timeStr => {
dates.push(new Date(timeStr));
});
let temperatures = jrez.daily.temperature_2m_max
// console.log({dates,temperatures});
return {dates,temperatures};
}
}

export default WeatherUtil;
Loading

0 comments on commit 8e8a939

Please sign in to comment.