Skip to content

Commit 9b2020e

Browse files
authored
Merge pull request #82 from Navigraph/feat/add-packages-api
Add packages API
2 parents 1b73742 + a2c6274 commit 9b2020e

28 files changed

+471
-67
lines changed

.changeset/slow-carrots-work.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"getting-started": patch
3+
"navigraph": patch
4+
"@navigraph/packages": major
5+
"@navigraph/app": patch
6+
---
7+
8+
Added `@navigraph/packages` module for interactions with the packages-api.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ yarn-error.log*
2828
.env.development.local
2929
.env.test.local
3030
.env.production.local
31+
.env
3132

3233
# turbo
3334
.turbo

examples/getting-started/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"react-dom": "^18.2.0",
1515
"@navigraph/app": "*",
1616
"@navigraph/auth": "*",
17-
"@navigraph/charts": "*"
17+
"@navigraph/charts": "*",
18+
"@navigraph/packages": "*"
1819
},
1920
"devDependencies": {
2021
"@types/react": "^18.2.15",

examples/getting-started/src/App.tsx

Lines changed: 59 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,79 @@
1-
import { DeviceFlowParams } from "navigraph/auth";
2-
import { useCallback, useState } from "react";
3-
import { useNavigraphAuth } from "./hooks/useNavigraphAuth";
4-
import { charts } from "./lib/navigraph";
1+
import { NoPackagesFoundError, RequestFailedError } from "@navigraph/app"
2+
import { NavigraphPackage } from "@navigraph/packages"
3+
import { useCallback, useState } from "react"
4+
import Auth from "./components/Auth"
5+
import Button from "./components/Button"
6+
import { useNavigraphAuth } from "./hooks/useNavigraphAuth"
7+
import { charts, packages } from "./lib/navigraph"
8+
9+
const AIRPORT_ICAO = "KJFK"
510

611
function App() {
7-
const [params, setParams] = useState<DeviceFlowParams | null>(null);
8-
const [chartsIndex, setChartsIndex] = useState<string | undefined>(undefined);
12+
const [output, setOutput] = useState<string | undefined>(undefined)
13+
const [packageDetails, setPackageDetails] = useState<NavigraphPackage | undefined>(undefined)
14+
const [errorMessage, setErrorMessage] = useState<string | undefined>(undefined)
15+
16+
const { user } = useNavigraphAuth()
917

10-
const { user, isInitialized, signIn, signOut } = useNavigraphAuth();
18+
const handleNavigraphError = useCallback(
19+
(error: unknown) => {
20+
if (error instanceof NoPackagesFoundError) setErrorMessage("No packages found")
21+
else if (error instanceof RequestFailedError) setErrorMessage("Failed to fetch packages")
22+
else if (error instanceof Error) setErrorMessage("An unknown error occurred")
23+
else setErrorMessage("An unknown error occurred: " + error)
24+
},
25+
[setErrorMessage],
26+
)
1127

12-
const fetchChartsIndex = () =>
13-
charts.getChartsIndex({ icao: "KJFK" }).then((d) => setChartsIndex(JSON.stringify(d, null, 2)));
28+
const listCharts = () =>
29+
charts
30+
.getChartsIndex({ icao: AIRPORT_ICAO })
31+
.then(charts => setOutput(JSON.stringify(charts, null, 2)))
32+
.catch(err => handleNavigraphError(err))
1433

15-
const handleSignIn = useCallback(
16-
() => signIn((p) => setParams(p)).finally(() => setParams(null)),
17-
[signIn]
18-
);
34+
const fetchPackage = () =>
35+
packages
36+
.getPackage()
37+
.then(pkg => setPackageDetails(pkg))
38+
.catch(err => handleNavigraphError(err))
1939

20-
const isLoginInProgress = !!params;
40+
const listPackages = () =>
41+
packages
42+
.listPackages()
43+
.then(pkgs => setOutput(JSON.stringify(pkgs, null, 2)))
44+
.catch(err => handleNavigraphError(err))
2145

2246
return (
2347
<main className="dark:bg-black dark:text-white flex flex-col space-y-10 items-center justify-center min-h-screen ">
24-
{!isInitialized && <div>Loading...</div>}
25-
2648
<h1 className="text-6xl text-black dark:text-white font-bold">Navigraph SDK Demo</h1>
2749

28-
<button
29-
className="py-2 px-4 font-semibold rounded-md bg-black text-white dark:bg-white dark:text-black"
30-
onClick={() => !isLoginInProgress && (user ? signOut() : handleSignIn())}
31-
>
32-
{user ? "Sign out" : !isLoginInProgress ? "Sign in" : "Signing in..."}
33-
</button>
34-
35-
{params?.verification_uri_complete && !user && (
36-
<div className="flex flex-col items-center gap-2">
37-
<a
38-
href={params.verification_uri_complete}
39-
className="text-blue-600 bg-gray-500/10 p-3 rounded-lg"
40-
target="_blank"
41-
rel="noreferrer"
42-
>
43-
Open sign in page
44-
</a>
45-
<span className="opacity-50">or scan this QR code:</span>
46-
<div className="p-2 rounded-lg bg-white mt-1">
47-
<img
48-
src={`https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=${params.verification_uri_complete}`}
49-
/>
50-
</div>
51-
</div>
52-
)}
50+
<Auth />
5351

5452
{user && (
5553
<>
56-
<h2 className="text-2xl">
57-
Welcome, <span className="text-blue-400 font-bold">{user.preferred_username}</span>
58-
</h2>
59-
<button
60-
onClick={fetchChartsIndex}
61-
className="bg-white text-black py-2 px-4 font-semibold rounded-md"
62-
>
63-
Fetch charts index
64-
</button>
54+
<div className="flex flex-col items-center space-y-2">
55+
<h2 className="text-2xl mb-2">
56+
Welcome, <span className="text-blue-400 font-bold">{user.preferred_username}</span>
57+
</h2>
58+
59+
<Button onClick={listCharts}>List {AIRPORT_ICAO} charts</Button>
60+
<Button onClick={listPackages}>List available packages</Button>
61+
<Button onClick={fetchPackage}>Fetch default package</Button>
62+
63+
{packageDetails && (
64+
<a href={packageDetails.file?.url} className="text-blue-500 hover:text-blue-700">
65+
Download {packageDetails.format}
66+
</a>
67+
)}
68+
69+
{errorMessage && <span className="text-red-500 hover:text-red-700">{errorMessage}</span>}
70+
</div>
6571
</>
6672
)}
6773

68-
{chartsIndex && <pre className="text-sm max-h-[40vh] overflow-auto">{chartsIndex}</pre>}
74+
{output && <pre className="text-sm max-h-[40vh] max-w-[90vw] overflow-auto">{output}</pre>}
6975
</main>
70-
);
76+
)
7177
}
7278

73-
export default App;
79+
export default App
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { DeviceFlowTokenExpiredError } from "@navigraph/app"
2+
import { DeviceFlowParams } from "@navigraph/auth"
3+
import { useCallback, useState } from "react"
4+
import { useNavigraphAuth } from "../hooks/useNavigraphAuth"
5+
6+
export default function Auth() {
7+
const [error, setError] = useState<Error | null>(null)
8+
const [params, setParams] = useState<DeviceFlowParams | null>(null)
9+
const { user, isInitialized, signIn, signOut } = useNavigraphAuth()
10+
11+
const handleSignIn = useCallback(
12+
() =>
13+
signIn(params => {
14+
setParams(params)
15+
setError(null)
16+
})
17+
.catch(err => setError(err))
18+
.finally(() => setParams(null)),
19+
[signIn],
20+
)
21+
22+
const isLoginInProgress = !!params
23+
24+
return (
25+
<>
26+
{!isInitialized && <div>Loading...</div>}
27+
28+
{isInitialized && (
29+
<button
30+
className="py-2 px-4 font-semibold rounded-md bg-black text-white dark:bg-white dark:text-black"
31+
onClick={() => !isLoginInProgress && (user ? signOut() : handleSignIn())}>
32+
{user ? "Sign out" : !isLoginInProgress ? "Sign in" : "Signing in..."}
33+
</button>
34+
)}
35+
36+
{error && (
37+
<div className="text-red-500">
38+
{error instanceof DeviceFlowTokenExpiredError ? "Session expired, try again!" : error.message}
39+
</div>
40+
)}
41+
42+
{params?.verification_uri_complete && !user && (
43+
<div className="flex flex-col items-center gap-2">
44+
<a
45+
href={params.verification_uri_complete}
46+
className="text-blue-600 bg-gray-500/10 p-3 rounded-lg"
47+
target="_blank"
48+
rel="noreferrer">
49+
Open sign in page
50+
</a>
51+
<span className="opacity-50">or scan this QR code:</span>
52+
<div className="p-2 rounded-lg bg-white mt-1">
53+
<img
54+
src={`https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=${params.verification_uri_complete}`}
55+
alt="QR Code for sign in."
56+
/>
57+
</div>
58+
</div>
59+
)}
60+
</>
61+
)
62+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React from "react"
2+
3+
export default function Button(props: React.HTMLAttributes<HTMLButtonElement>) {
4+
return (
5+
<button
6+
className="bg-black dark:bg-white text-white dark:text-black py-2 px-4 font-semibold rounded-md"
7+
{...props}
8+
/>
9+
)
10+
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
import { initializeApp, NavigraphApp, Scope } from "@navigraph/app"
22
import { getAuth } from "@navigraph/auth"
33
import { getChartsAPI } from "@navigraph/charts"
4+
import { getPackagesAPI } from "@navigraph/packages"
45

56
const config: NavigraphApp = {
67
clientId: import.meta.env.NG_CLIENT_ID,
78
clientSecret: import.meta.env.NG_CLIENT_SECRET,
89
scopes: [Scope.CHARTS, Scope.FMSDATA],
910
}
1011

11-
if (config.clientId.includes("<")) {
12+
if (!config.clientId || config.clientId.includes("<")) {
1213
alert("Please add your client credentials in lib/navigraph.ts.")
1314
}
1415

1516
initializeApp(config)
1617

1718
export const auth = getAuth()
1819
export const charts = getChartsAPI()
20+
export const packages = getPackagesAPI()

packages/app/src/shared/errors.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,17 @@ export class NonGeoreferencedChartError extends Error {
4747
this.name = "NonGeoreferencedChartError"
4848
}
4949
}
50+
51+
export class NoPackagesFoundError extends Error {
52+
constructor() {
53+
super("No packages found")
54+
this.name = "NoPackagesFoundError"
55+
}
56+
}
57+
58+
export class RequestFailedError extends Error {
59+
constructor(resource: string, reason?: string) {
60+
super(`Failed to fetch ${resource}${reason ? `. Reason: ${reason}` : ""}`)
61+
this.name = "RequestFailedError"
62+
}
63+
}

packages/charts/package.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,5 @@
3737
"dependencies": {
3838
"@navigraph/auth": "2.5.0",
3939
"@navigraph/app": "1.3.4"
40-
},
41-
"devDependencies": {
42-
"@types/leaflet": "^1.9.3"
4340
}
4441
}

packages/leaflet/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"leaflet": "^1.9.4"
4242
},
4343
"devDependencies": {
44-
"@navigraph/auth": "2.5.0"
44+
"@navigraph/auth": "2.5.0",
45+
"@types/leaflet": "^1.9.3"
4546
}
4647
}

0 commit comments

Comments
 (0)