@minnai/create-aura-app 0.0.28 → 0.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -6,33 +6,19 @@ export function useStocksLogic(props: any) {
|
|
|
6
6
|
const [data, setData] = useState<any>(null);
|
|
7
7
|
const [loading, setLoading] = useState(false);
|
|
8
8
|
const [error, setError] = useState<string | null>(null);
|
|
9
|
-
const [apiKeyMissing, setApiKeyMissing] = useState(false);
|
|
10
9
|
|
|
11
10
|
const { resources } = props;
|
|
12
|
-
const apiKey = resources?.keys?.STOCKS_API_KEY;
|
|
13
11
|
const apiConfig = resources?.api?.stocks?.timeSeries?.config;
|
|
14
12
|
|
|
15
13
|
useEffect(() => {
|
|
16
|
-
if (!apiKey || apiKey === 'YOUR_API_KEY' || apiKey.length < 5) {
|
|
17
|
-
setApiKeyMissing(true);
|
|
18
|
-
flux.dispatch({
|
|
19
|
-
type: 'AIR_ERROR',
|
|
20
|
-
payload: {
|
|
21
|
-
airId: 'stocks-air',
|
|
22
|
-
error: '🚨 STOCKS_API_KEY is missing in resources.ts!'
|
|
23
|
-
},
|
|
24
|
-
to: 'all'
|
|
25
|
-
});
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
14
|
fetchStock(symbol);
|
|
29
|
-
}, [
|
|
15
|
+
}, [symbol]);
|
|
30
16
|
|
|
31
17
|
const fetchStock = async (sym: string) => {
|
|
32
18
|
setLoading(true);
|
|
33
19
|
setError(null);
|
|
34
20
|
try {
|
|
35
|
-
const url = `${apiConfig.url}?function=${apiConfig.params.function}&symbol=${sym}
|
|
21
|
+
const url = `${apiConfig.url}?function=${apiConfig.params.function}&symbol=${sym}`;
|
|
36
22
|
const response = await fetch(url);
|
|
37
23
|
const json = await response.json();
|
|
38
24
|
|
|
@@ -83,5 +69,5 @@ export function useStocksLogic(props: any) {
|
|
|
83
69
|
}
|
|
84
70
|
};
|
|
85
71
|
|
|
86
|
-
return { symbol, setSymbol, data, loading, error,
|
|
72
|
+
return { symbol, setSymbol, data, loading, error, fetchStock };
|
|
87
73
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Get a free key at: https://www.alphavantage.co/support/#api-key
|
|
1
|
+
// AlphaVantage API key is handled by the proxy
|
|
3
2
|
export const resources = {
|
|
4
3
|
api: {
|
|
5
4
|
stocks: {
|
|
@@ -16,10 +15,5 @@ export const resources = {
|
|
|
16
15
|
}
|
|
17
16
|
}
|
|
18
17
|
}
|
|
19
|
-
},
|
|
20
|
-
keys: {
|
|
21
|
-
STOCKS_API_KEY: null
|
|
22
18
|
}
|
|
23
19
|
} as const;
|
|
24
|
-
|
|
25
|
-
export const STOCKS_API_KEY = null;
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { LineChart, Line, ResponsiveContainer, YAxis, Tooltip } from 'recharts';
|
|
3
3
|
|
|
4
4
|
export default function StocksUI({
|
|
5
|
-
symbol, setSymbol, data, loading, error,
|
|
5
|
+
symbol, setSymbol, data, loading, error, onSearch
|
|
6
6
|
}: any) {
|
|
7
7
|
const isPositive = data && parseFloat(data.change) >= 0;
|
|
8
8
|
|
|
@@ -10,57 +10,48 @@ export default function StocksUI({
|
|
|
10
10
|
<div style={{ paddingTop: 0, height: '100%', display: 'flex', flexDirection: 'column' }}>
|
|
11
11
|
<div style={{ marginTop: 10, fontSize: '0.8rem', fontWeight: 600, textTransform: 'uppercase', color: '#888', letterSpacing: '0.5px' }}>Market Data</div>
|
|
12
12
|
|
|
13
|
-
{
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
<input
|
|
22
|
-
value={symbol}
|
|
23
|
-
onChange={(e) => setSymbol(e.target.value.toUpperCase())}
|
|
24
|
-
placeholder="Enter Symbol (e.g. AAPL)"
|
|
25
|
-
style={{ width: '100%', padding: '10px', borderRadius: 8, border: '1px solid #ddd', outline: 'none' }}
|
|
26
|
-
/>
|
|
27
|
-
</form>
|
|
28
|
-
|
|
29
|
-
{loading && <div style={{ textAlign: 'center', color: '#666' }}>Loading...</div>}
|
|
30
|
-
{error && <div style={{ color: 'red', textAlign: 'center' }}>{error}</div>}
|
|
13
|
+
<form onSubmit={(e) => { e.preventDefault(); onSearch(symbol); }} style={{ marginBottom: 10 }}>
|
|
14
|
+
<input
|
|
15
|
+
value={symbol}
|
|
16
|
+
onChange={(e) => setSymbol(e.target.value.toUpperCase())}
|
|
17
|
+
placeholder="Enter Symbol (e.g. AAPL)"
|
|
18
|
+
style={{ width: '100%', padding: '10px', borderRadius: 8, border: '1px solid #ddd', outline: 'none' }}
|
|
19
|
+
/>
|
|
20
|
+
</form>
|
|
31
21
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
<div style={{ textAlign: 'center', marginBottom: 10 }}>
|
|
35
|
-
<h2 style={{ fontSize: '2rem', margin: '0 0 5px 0', fontWeight: 800 }}>{data.price}</h2>
|
|
36
|
-
<div style={{ fontSize: '1.2rem', color: isPositive ? '#00c853' : '#d32f2f', fontWeight: 600 }}>
|
|
37
|
-
{isPositive ? '▲' : '▼'} {data.change} ({data.changePercent})
|
|
38
|
-
</div>
|
|
39
|
-
<div style={{ color: '#999', fontSize: '0.8rem' }}>{data.symbol} - Last 30 Days</div>
|
|
40
|
-
</div>
|
|
22
|
+
{loading && <div style={{ textAlign: 'center', color: '#666' }}>Loading...</div>}
|
|
23
|
+
{error && <div style={{ color: 'red', textAlign: 'center' }}>{error}</div>}
|
|
41
24
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
itemStyle={{ color: '#333' }}
|
|
49
|
-
formatter={(value: any) => [parseFloat(value).toFixed(2), 'Price']}
|
|
50
|
-
/>
|
|
51
|
-
<Line
|
|
52
|
-
type="monotone"
|
|
53
|
-
dataKey="price"
|
|
54
|
-
stroke={isPositive ? '#00c853' : '#d32f2f'}
|
|
55
|
-
strokeWidth={2}
|
|
56
|
-
dot={false}
|
|
57
|
-
/>
|
|
58
|
-
</LineChart>
|
|
59
|
-
</ResponsiveContainer>
|
|
60
|
-
</div>
|
|
25
|
+
{data && !loading && (
|
|
26
|
+
<div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
|
|
27
|
+
<div style={{ textAlign: 'center', marginBottom: 10 }}>
|
|
28
|
+
<h2 style={{ fontSize: '2rem', margin: '0 0 5px 0', fontWeight: 800 }}>{data.price}</h2>
|
|
29
|
+
<div style={{ fontSize: '1.2rem', color: isPositive ? '#00c853' : '#d32f2f', fontWeight: 600 }}>
|
|
30
|
+
{isPositive ? '▲' : '▼'} {data.change} ({data.changePercent})
|
|
61
31
|
</div>
|
|
62
|
-
|
|
63
|
-
|
|
32
|
+
<div style={{ color: '#999', fontSize: '0.8rem' }}>{data.symbol} - Last 30 Days</div>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div style={{ flex: 1, minHeight: 150, width: '100%' }}>
|
|
36
|
+
<ResponsiveContainer width="100%" height="100%">
|
|
37
|
+
<LineChart data={data.history}>
|
|
38
|
+
<YAxis domain={['auto', 'auto']} hide={true} />
|
|
39
|
+
<Tooltip
|
|
40
|
+
contentStyle={{ borderRadius: 8, border: 'none', boxShadow: '0 2px 10px rgba(0,0,0,0.1)' }}
|
|
41
|
+
itemStyle={{ color: '#333' }}
|
|
42
|
+
formatter={(value: any) => [parseFloat(value).toFixed(2), 'Price']}
|
|
43
|
+
/>
|
|
44
|
+
<Line
|
|
45
|
+
type="monotone"
|
|
46
|
+
dataKey="price"
|
|
47
|
+
stroke={isPositive ? '#00c853' : '#d32f2f'}
|
|
48
|
+
strokeWidth={2}
|
|
49
|
+
dot={false}
|
|
50
|
+
/>
|
|
51
|
+
</LineChart>
|
|
52
|
+
</ResponsiveContainer>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
64
55
|
)}
|
|
65
56
|
</div>
|
|
66
57
|
);
|
|
@@ -5,6 +5,12 @@ import fs from 'fs';
|
|
|
5
5
|
|
|
6
6
|
// https://vite.dev/config/
|
|
7
7
|
export default defineConfig({
|
|
8
|
+
resolve: {
|
|
9
|
+
alias: {
|
|
10
|
+
react: path.resolve(__dirname, 'node_modules/react'),
|
|
11
|
+
'react-dom': path.resolve(__dirname, 'node_modules/react-dom'),
|
|
12
|
+
},
|
|
13
|
+
},
|
|
8
14
|
plugins: [
|
|
9
15
|
react(),
|
|
10
16
|
{
|