Skip to content

Commit

Permalink
Merge pull request #85 from mnsrulz/main
Browse files Browse the repository at this point in the history
sync: main to stage
  • Loading branch information
mnsrulz authored Nov 10, 2024
2 parents d06ecb8 + ad55a81 commit f803355
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 77 deletions.
77 changes: 12 additions & 65 deletions src/app/history/page.tsx
Original file line number Diff line number Diff line change
@@ -1,72 +1,16 @@
'use client';
import { useCachedReleaseData, useCachedReleaseSymbolData, useMyStockList } from '@/lib/socket';
import { Dialog, DialogContent, DialogTitle, FormControl, Grid, ImageList, ImageListItem, InputLabel, LinearProgress, Link, MenuItem, Select, useMediaQuery, useTheme } from '@mui/material';
import { useCachedReleaseData, useMyStockList } from '@/lib/socket';
import { FormControl, FormControlLabel, Grid, InputLabel, LinearProgress, MenuItem, Select, Switch } from '@mui/material';
import { useState } from 'react';
import { IconButton} from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';
const D1 = (props: { dt: string, mytickersSymbols: string[] }) => {
const { dt, mytickersSymbols } = props;
const { cachedSummarySymbolsData } = useCachedReleaseSymbolData(dt);
const theme = useTheme();
const matchesXs = useMediaQuery(theme.breakpoints.down("sm"));
const matchesMd = useMediaQuery(theme.breakpoints.down("md"));
const numberOfItemsToDisplay = matchesXs ? 2 : matchesMd ? 3 : 4;
const ts = cachedSummarySymbolsData.filter(r => mytickersSymbols.includes(r.name)); //make sure to load only those which are part of the watchlist.
import { HistoricalDex } from '@/components/HistoricalDex';

const [openDialog, setOpenDialog] = useState(false);
const [selectedImage, setSelectedImage] = useState('');

const handleImageClick = (imageSrc: string) => {
setSelectedImage(imageSrc);
setOpenDialog(true);
};

const handleCloseDialog = () => {
setOpenDialog(false);
};
return <><ImageList cols={numberOfItemsToDisplay} gap={1}>
{ts.map((item) => (
<ImageListItem key={item.name} sx={{ width: '100%', height: '100px' }}>
<img src={`https://mztrading-data.deno.dev/images?dt=${dt}&s=${item.name}`}
style={{ width: '100%', height: 'auto', objectFit: 'cover',
transition: 'all 0.3s ease-in-out',
cursor: 'pointer',
// boxShadow: '0 0 10px rgba(0, 0, 0, 0.2)',
// '&:hover': {
// boxShadow: '0 0 20px rgba(0, 0, 0, 0.5)',
// transform: 'scale(1.05)',
// }

}}
loading="lazy"
onClick={() => handleImageClick(`https://mztrading-data.deno.dev/images?dt=${dt}&s=${item.name}`)} />
</ImageListItem>
))}
</ImageList>
<Dialog open={openDialog} onClose={handleCloseDialog} fullScreen={matchesXs}>
<DialogTitle>
<IconButton
aria-label="close"
onClick={handleCloseDialog}
sx={{ position: 'absolute', right: 8, top: 8 }}
>
<CloseIcon />
</IconButton>
</DialogTitle>
<DialogContent>
<img src={selectedImage} style={{ width: '100%', objectFit: 'contain' }} />
</DialogContent>
</Dialog>
</>;
}

export default function Page() {
const { mytickers, loading } = useMyStockList();
export default function Page() {
const [showAllSymbols, setShowAllSymbols] = useState(false);
const { cachedSummaryData, isLoadingCachedSummaryData } = useCachedReleaseData();
const [dataMode, setDataMode] = useState('');
if (isLoadingCachedSummaryData || loading) return <LinearProgress />;
if (isLoadingCachedSummaryData) return <LinearProgress />;
const cachedDates = cachedSummaryData.map(j => j.name);
const mytickersSymbols = mytickers.map(r => r.symbol)

const dt = dataMode || cachedDates.at(0) || '';
return (
<>
Expand All @@ -85,9 +29,12 @@ export default function Page() {
}
</Select>
</FormControl>
<Link href='history/legacy'>Legacy Mode</Link>
<FormControl sx={{ m: 1, minWidth: 120 }} size="small">
<FormControlLabel title='Show all symbols available for a given date or limit symbols available in your watchlist' control={<Switch checked={showAllSymbols} onChange={(e, v) => setShowAllSymbols(v)} />} label="Show all?" />
</FormControl>
{/* <Link href='history/legacy'>Legacy Mode</Link> */}
<Grid container>
<D1 dt={dt} mytickersSymbols={mytickersSymbols} ></D1>
<HistoricalDex dt={dt} showAllSymbols={showAllSymbols} />
</Grid></>
);
}
65 changes: 65 additions & 0 deletions src/components/HistoricalDex.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
'use client';
import { useCachedReleaseSymbolData } from '@/lib/socket';
import { Dialog, DialogContent, DialogTitle, ImageList, ImageListItem, useMediaQuery, useTheme } from '@mui/material';
import { useState } from 'react';
import { IconButton } from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';
import { useMyLocalWatchList } from '@/lib/hooks';
export const HistoricalDex = (props: { dt: string, showAllSymbols: boolean }) => {
const { wl } = useMyLocalWatchList([]);
const mytickersSymbols = wl.map(r => r.symbol);
const { dt, showAllSymbols } = props;
const { cachedSummarySymbolsData } = useCachedReleaseSymbolData(dt);
const theme = useTheme();
const matchesXs = useMediaQuery(theme.breakpoints.down("sm"));
const matchesMd = useMediaQuery(theme.breakpoints.down("md"));
const numberOfItemsToDisplay = matchesXs ? 2 : matchesMd ? 3 : 4;
const ts = cachedSummarySymbolsData.filter(r => showAllSymbols || mytickersSymbols.includes(r.name)); //make sure to load only those which are part of the watchlist.

const [openDialog, setOpenDialog] = useState(false);
const [selectedImage, setSelectedImage] = useState('');

const handleImageClick = (imageSrc: string) => {
setSelectedImage(imageSrc);
setOpenDialog(true);
};

const handleCloseDialog = () => {
setOpenDialog(false);
};
return <><ImageList cols={numberOfItemsToDisplay} gap={1}>
{ts.map((item) => (
<ImageListItem key={item.name} sx={{ width: '100%', height: '100px' }}>
<img src={`https://mztrading-data.deno.dev/images?dt=${dt}&s=${item.name}`}
style={{
width: '100%', height: 'auto', objectFit: 'cover',
transition: 'all 0.3s ease-in-out',
cursor: 'pointer',
// boxShadow: '0 0 10px rgba(0, 0, 0, 0.2)',
// '&:hover': {
// boxShadow: '0 0 20px rgba(0, 0, 0, 0.5)',
// transform: 'scale(1.05)',
// }

}}
loading="lazy"
onClick={() => handleImageClick(`https://mztrading-data.deno.dev/images?dt=${dt}&s=${item.name}`)} />
</ImageListItem>
))}
</ImageList>
<Dialog open={openDialog} onClose={handleCloseDialog} fullScreen={matchesXs}>
<DialogTitle>
<IconButton
aria-label="close"
onClick={handleCloseDialog}
sx={{ position: 'absolute', right: 8, top: 8 }}
>
<CloseIcon />
</IconButton>
</DialogTitle>
<DialogContent>
<img src={selectedImage} style={{ width: '100%', objectFit: 'contain' }} />
</DialogContent>
</Dialog>
</>;
}
27 changes: 17 additions & 10 deletions src/components/Watchlist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import * as React from 'react';
import DeleteIcon from '@mui/icons-material/Delete';
import InfoIcon from '@mui/icons-material/Info';
import { Button, Dialog, DialogContent, DialogTitle, FormControl, InputLabel, MenuItem, Select } from '@mui/material';
import { Button, Dialog, DialogContent, DialogTitle, FormControl, MenuItem, Select } from '@mui/material';
import { DataGrid, GridActionsCellItem, GridColDef, useGridApiRef } from '@mui/x-data-grid';
import { useEffect, useState } from 'react';
import { StockTickerSymbolView, StockTickerView } from './StockTicker';
Expand All @@ -14,6 +14,7 @@ import { TickerSearch } from './TickerSearch';
import { TradingViewWidgetDialog } from './TradingViewWidgetDialog';
import { subscribeStockPriceBatchRequest } from '@/lib/socket';
import collect from 'collect.js';
import { useMyLocalWatchList } from '@/lib/hooks';

interface IWatchlistProps {
tickers: SearchTickerItem[]
Expand All @@ -23,18 +24,20 @@ interface IWatchlistProps {
}

export const Watchlist = (props: IWatchlistProps) => {
const { tickers, removFromWatchlist, loading, addToWatchlist } = props;
const { tickers, loading, addToWatchlist } = props;
const { wl , removeFromMyList, addToMyList} = useMyLocalWatchList(tickers);

const apiRef = useGridApiRef();
const [currentStock, setCurrentStock] = useState<SearchTickerItem | null>(null);
const [sortMode, setSortMode] = useState('symbol');

useEffect(() => {
const interval = setInterval(() => {
subscribeStockPriceBatchRequest(tickers);
subscribeStockPriceBatchRequest(wl);
}, 1000); //every one second just ping the server to resubscribe

return () => clearInterval(interval);
}, [tickers]);
}, [wl]);

const columns: GridColDef<SearchTickerItem>[] = [
{
Expand All @@ -57,13 +60,13 @@ export const Watchlist = (props: IWatchlistProps) => {
}, renderHeader: () => {
return <>Sort <FormControl variant="standard" sx={{ m: 1, minWidth: 120 }} size='small'>
{/* <InputLabel id="sort-by-label">Sort by</InputLabel> */}

<Select
labelId="sort-by-label"
value={sortMode}
onChange={(e) => setSortMode(e.target.value)}
label="Sort by"
size='small'
size='small'
autoWidth
>
<MenuItem value="symbol">Ticker</MenuItem>
Expand All @@ -81,7 +84,8 @@ export const Watchlist = (props: IWatchlistProps) => {
key='Remove'
icon={<DeleteIcon />}
label="Remove from my list"
onClick={() => removFromWatchlist(row)}
// onClick={() => removFromWatchlist(row)}
onClick={() => removeFromMyList(row)}
showInMenu
/>,
<GridLinkAction
Expand Down Expand Up @@ -123,13 +127,16 @@ export const Watchlist = (props: IWatchlistProps) => {
const [openAddToWatchlist, setOpenAddToWatchlist] = useState(false);

const handleCloseAddTrade = () => { setOpenAddTrade(false); };
const handleAddToWatchlist = (item: SearchTickerItem) => { addToWatchlist(item); setOpenAddToWatchlist(false); }
const handleAddToWatchlist = (item: SearchTickerItem) => {
addToWatchlist(item); setOpenAddToWatchlist(false);
addToMyList(item);
}

return <div>
{/* <Typography variant='body2'>Watchlist</Typography> */}


<DataGrid rows={collect(tickers).sortBy(sortMode).all()}
<DataGrid rows={collect(wl).sortBy(sortMode).all()}
columns={columns}
//sx={{ '& .MuiDataGrid-columnSeparator': { display: 'none' } }}
sx={{ display: 'grid', '& .MuiDataGrid-columnSeparator': { display: 'none' } }}
Expand Down
24 changes: 22 additions & 2 deletions src/lib/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,33 @@
'use client';
import { useCallback, useState } from "react"
import { useLocalStorage } from "@uidotdev/usehooks";
import { SearchTickerItem } from "./types";

export const useShowCloseTrades = () => {
const [showCloseTrades, setShowCloseTrades] = useState((typeof window !== "undefined" ? window?.localStorage?.getItem("showCloseTrades") == 'true': false) || false);
const [showCloseTrades, setShowCloseTrades] = useState((typeof window !== "undefined" ? window?.localStorage?.getItem("showCloseTrades") == 'true' : false) || false);
const toggleShowCloseTrades = useCallback((newstate: boolean) => {
setShowCloseTrades(newstate);
window?.localStorage?.setItem("showCloseTrades", `${newstate}`);
}, []);

return {showCloseTrades, toggleShowCloseTrades }
return { showCloseTrades, toggleShowCloseTrades }
}

export const useMyLocalWatchList = (initialState: SearchTickerItem[]) => {
const [wl, setWl] = useLocalStorage("localwatchlist", initialState);

const removeFromMyList = (item: SearchTickerItem) => {
setWl(v => v.filter((ticker) => ticker.symbol != item.symbol));
}

const addToMyList = (item: SearchTickerItem) => {
setWl(v => {
v.push(item)
return v;
});
}

return { wl, removeFromMyList, addToMyList }
}


0 comments on commit f803355

Please sign in to comment.