-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parts and robots #46
Parts and robots #46
Changes from 12 commits
a704fea
8aaa3b0
129cd27
ce65ca4
dfaf27f
5a73fd9
ca37d7d
fb54ec6
632cc58
d6b5dae
de9e08a
236bd11
f72e870
50717bc
3d35a71
ca8d490
f280dc6
4c9fa7b
0a76a47
8b10b6c
ffab9cb
146c1e5
35af3ce
e994314
5f803d0
0bc5936
a65dae9
c7f9a40
3590f62
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import axios from "axios"; | ||
|
||
interface PurchaseLink { | ||
url: string; | ||
price: number; | ||
name: string; | ||
} | ||
|
||
interface UsedBy { | ||
name: string; | ||
id: string; | ||
stars: number; | ||
} | ||
|
||
interface Part { | ||
name: string; | ||
owner: string; | ||
description: string; | ||
images: Image[]; | ||
part_id: string; | ||
used_by: UsedBy[]; | ||
purchase_links: PurchaseLink[]; | ||
} | ||
interface Bom { | ||
id: string; | ||
name: string; | ||
quantity: number; | ||
price: number; | ||
} | ||
|
||
interface Image { | ||
caption: string; | ||
url: string; | ||
} | ||
|
||
interface Robot { | ||
robot_id: string; | ||
name: string; | ||
description: string; | ||
owner: string; | ||
bom: Bom[]; | ||
images: Image[]; | ||
} | ||
|
||
class rob { | ||
private api; | ||
|
||
constructor(baseURL: string | undefined) { | ||
this.api = axios.create({ baseURL }); | ||
} | ||
public async getRobots(): Promise<Robot[]> { | ||
try { | ||
const response = await this.api.get("/robots"); | ||
return response.data; | ||
} catch (error) { | ||
if (axios.isAxiosError(error)) { | ||
console.error("Error fetching robots:", error.response?.data); | ||
throw new Error( | ||
error.response?.data?.detail || "Error fetching robots", | ||
); | ||
} else { | ||
console.error("Unexpected error:", error); | ||
throw new Error("Unexpected error"); | ||
} | ||
} | ||
} | ||
public async getRobotById(robotId: string | undefined): Promise<Robot> { | ||
try { | ||
const response = await this.api.get(`/robots/${robotId}`); | ||
return response.data; | ||
} catch (error) { | ||
if (axios.isAxiosError(error)) { | ||
console.error("Error fetching robot:", error.response?.data); | ||
throw new Error(error.response?.data?.detail || "Error fetching robot"); | ||
} else { | ||
console.error("Unexpected error:", error); | ||
throw new Error("Unexpected error"); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this pattern is repeated 3 times, consider refactoring into a helper function (might need to do some typing voodoo to make work) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i feel like the effort to make it "generic" (there are a lot of subtly different args) would not be worthwhile atm |
||
} | ||
} | ||
public async getPartById(partId: string | undefined): Promise<Part> { | ||
try { | ||
const response = await this.api.get(`/parts/${partId}`); | ||
return response.data; | ||
} catch (error) { | ||
if (axios.isAxiosError(error)) { | ||
console.error("Error fetching robot:", error.response?.data); | ||
throw new Error(error.response?.data?.detail || "Error fetching robot"); | ||
} else { | ||
console.error("Unexpected error:", error); | ||
throw new Error("Unexpected error"); | ||
} | ||
} | ||
} | ||
public async getParts(): Promise<Part[]> { | ||
try { | ||
const response = await this.api.get("/parts"); | ||
return response.data; | ||
} catch (error) { | ||
if (axios.isAxiosError(error)) { | ||
console.error("Error fetching parts:", error.response?.data); | ||
throw new Error(error.response?.data?.detail || "Error fetching parts"); | ||
} else { | ||
console.error("Unexpected error:", error); | ||
throw new Error("Unexpected error"); | ||
} | ||
} | ||
} | ||
} | ||
|
||
export default new rob("http://127.0.0.1:8080/api"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't commit this to master, it is just for testing locally. use some env variable |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
import { useState } from "react"; | ||
import rob from "hooks/rob"; | ||
import { useEffect, useState } from "react"; | ||
codekansas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
import { | ||
Breadcrumb, | ||
Button, | ||
|
@@ -23,18 +24,57 @@ interface PartDetailsResponse { | |
const PartDetails = () => { | ||
const { id } = useParams(); | ||
const [show, setShow] = useState(false); | ||
const [part, setPart] = useState<PartDetailsResponse | null>(null); | ||
const [imageIndex, setImageIndex] = useState(0); | ||
const [error, setError] = useState<string | null>(null); | ||
|
||
const handleClose = () => setShow(false); | ||
const handleShow = () => setShow(true); | ||
|
||
useEffect(() => { | ||
const fetchPart = async () => { | ||
try { | ||
const partData = await rob.getPartById(id); | ||
setPart(partData); | ||
} catch (err) { | ||
if (err instanceof Error) { | ||
setError(err.message); | ||
} else { | ||
setError("An unexpected error occurred"); | ||
} | ||
} | ||
}; | ||
fetchPart(); | ||
}, [id]); | ||
|
||
const navigate = useNavigate(); | ||
|
||
useEffect(() => { | ||
if (error) { | ||
navigate("/404"); // Redirect to a 404 page | ||
} | ||
}, [error, navigate]); | ||
|
||
if (!part) { | ||
return <p>Loading</p>; | ||
} | ||
|
||
const response: PartDetailsResponse = { | ||
name: part.name, | ||
owner: part.owner, | ||
description: part.description, | ||
images: part.images, | ||
purchase_links: part.purchase_links, | ||
used_by: part.used_by, | ||
}; | ||
/* | ||
// This is a placeholder before the backend is hooked up. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can just delete instead of commenting out |
||
const response: PartDetailsResponse = { | ||
name: "RMD X8", | ||
owner: "MyActuator", | ||
description: `The RMD X8 is a quasi-direct drive motor from MyActuator.`, | ||
images: [ | ||
{ | ||
{ | ||
url: "https://media.robolist.xyz/rmd_x8.png", | ||
caption: "Actuator 1", | ||
}, | ||
|
@@ -62,11 +102,9 @@ const PartDetails = () => { | |
}, | ||
], | ||
}; | ||
|
||
*/ | ||
const { name, owner, description, images } = response; | ||
|
||
const navigate = useNavigate(); | ||
|
||
return ( | ||
<> | ||
<Breadcrumb> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it possible to auto-generate these interfaces from the openapi.json file for the backend?