From 8236aa85e75a901e1f7855df18e0b12c53c3c54b Mon Sep 17 00:00:00 2001 From: bludnic Date: Wed, 22 May 2024 13:06:00 +0100 Subject: [PATCH 1/6] chore: rm frontend and processor apps --- apps/frontend/.env | 1 - apps/frontend/.eslintrc.js | 5 - apps/frontend/.gitignore | 40 ----- apps/frontend/Dockerfile | 80 --------- apps/frontend/README.md | 21 --- apps/frontend/jest.config.js | 29 --- apps/frontend/next-env.d.ts | 5 - apps/frontend/next.config.js | 30 ---- apps/frontend/package.json | 78 -------- .../public/exchanges/logos/64x64/binance.png | Bin 2050 -> 0 bytes .../public/exchanges/logos/64x64/bybit.png | Bin 418 -> 0 bytes .../public/exchanges/logos/64x64/coinbase.png | Bin 520 -> 0 bytes .../public/exchanges/logos/64x64/gateio.png | Bin 2212 -> 0 bytes .../public/exchanges/logos/64x64/kraken.png | Bin 2401 -> 0 bytes .../public/exchanges/logos/64x64/okx.png | Bin 420 -> 0 bytes apps/frontend/public/favicon.ico | Bin 13641 -> 0 bytes apps/frontend/public/logo.png | Bin 24642 -> 0 bytes apps/frontend/public/robots.txt | 2 - .../frontend/src/app/api/trpc/[trpc]/route.ts | 54 ------ .../src/app/dashboard/accounts/page.tsx | 12 -- .../src/app/dashboard/bot/[id]/page.tsx | 38 ---- .../src/app/dashboard/bot/info/page.tsx | 23 --- .../src/app/dashboard/grid-bot/[id]/page.tsx | 38 ---- .../app/dashboard/grid-bot/create/page.tsx | 16 -- .../src/app/dashboard/grid-bot/info/page.tsx | 23 --- .../src/app/dashboard/grid-bot/page.tsx | 17 -- apps/frontend/src/app/dashboard/layout.tsx | 65 ------- .../frontend/src/app/dashboard/login/page.tsx | 5 - apps/frontend/src/app/dashboard/page.tsx | 9 - apps/frontend/src/app/layout.tsx | 39 ---- apps/frontend/src/app/page.tsx | 6 - .../AccountsListTable/AccountsListTable.tsx | 121 ------------- .../AccountsListTableHead.tsx | 44 ----- .../AccountsListTableRow.tsx | 90 ---------- .../AccountsListTableToolbar.tsx | 78 -------- .../accounts/AccountsListTable/index.ts | 1 - .../CreateAccountDialog.tsx | 42 ----- .../CreateAccountForm/CreateAccountForm.tsx | 143 --------------- .../CreateAccountForm/UpdateAccountForm.tsx | 155 ---------------- .../fields/AccountIdField.tsx | 22 --- .../fields/AccountNameField.tsx | 29 --- .../CreateAccountForm/fields/ApiKeyField.tsx | 29 --- .../fields/ExchangeCodeField.tsx | 32 ---- .../fields/IsDemoAccountField.tsx | 22 --- .../fields/PassphraseField.tsx | 28 --- .../fields/SecretKeyField.tsx | 29 --- .../accounts/CreateAccountForm/types.ts | 7 - .../UpdateAccountDialog.tsx | 44 ----- .../src/components/accounts/loading.tsx | 24 --- .../frontend/src/components/accounts/page.tsx | 54 ------ .../BotActions/RunBotTemplateButton.tsx | 48 ----- .../bot/bot-details/BotChart/BotChart.tsx | 71 -------- .../bot/bot-details/BotChart/index.ts | 1 - .../bot-details/BotSettings/BotSettings.tsx | 33 ---- .../BotSettings/BotSettingsCard.tsx | 49 ----- .../bot/bot-details/BotSettings/index.ts | 1 - .../BotSettingsForm/BotSettingsForm.tsx | 45 ----- .../components/bot/bot-details/loading.tsx | 33 ---- .../src/components/bot/bot-details/page.tsx | 92 ---------- .../common/bot/BotStatusSwitcher.tsx | 113 ------------ .../common/bot/actions/BotActions.tsx | 9 - .../bot/actions/BotAdditionalActions.tsx | 54 ------ .../buttons/CronPlacePendingOrderButton.tsx | 101 ----------- .../bot/actions/buttons/DeleteBotButton.tsx | 92 ---------- .../actions/buttons/RunBotTemplateButton.tsx | 48 ----- .../actions/buttons/StartStopBotButton.tsx | 101 ----------- .../bot/actions/buttons/SyncOrdersButton.tsx | 49 ----- .../bot/settings/PairSettingListItem.tsx | 31 ---- .../common/bot/settings/SettingListItem.tsx | 31 ---- .../bot/settings/StatusSettingListItem.tsx | 26 --- .../smart-trades/ProfitsCard/Profit.tsx | 31 ---- .../ProfitsCard/ProfitDetails.tsx | 59 ------ .../smart-trades/ProfitsCard/ProfitItem.tsx | 47 ----- .../smart-trades/ProfitsCard/ProfitsCard.tsx | 71 -------- .../common/smart-trades/ProfitsCard/index.ts | 1 - .../NoActiveSmartTradesPlaceholder.tsx | 22 --- .../SmartTradesTable/SmartTradeStatus.tsx | 25 --- .../SmartTradesTable/SmartTradesTable.tsx | 57 ------ .../SmartTradesTable/SmartTradesTableHead.tsx | 32 ---- .../SmartTradesTable/SmartTradesTableItem.tsx | 89 --------- .../SmartTradesTable/constants.ts | 1 - .../smart-trades/SmartTradesTable/index.ts | 1 - .../debug/SyncClosedOrdersButton.tsx | 62 ------- .../bot-details/BotSettings/BotSettings.tsx | 70 -------- .../BotSettings/BotSettingsCard.tsx | 49 ----- .../grid-bot/bot-details/BotSettings/index.ts | 1 - .../GridBotSettings/GridBotSettings.tsx | 56 ------ .../GridBotSettings/SettingInput.tsx | 20 --- .../bot-details/GridBotSettings/index.ts | 1 - .../GridDetailChart/GridDetailChart.tsx | 109 ----------- .../bot-details/GridDetailChart/index.ts | 1 - .../utils/computePriceLines.ts | 31 ---- .../utils/computeTradeMarkers.ts | 130 -------------- .../grid-bot/bot-details/loading.tsx | 33 ---- .../components/grid-bot/bot-details/page.tsx | 92 ---------- .../grid-bot/bots-list/BotCard/BotCard.tsx | 166 ----------------- .../bots-list/BotCard/BotStatusIndicator.tsx | 53 ------ .../grid-bot/bots-list/BotCard/Bull.tsx | 13 -- .../grid-bot/bots-list/BotCard/index.ts | 1 - .../components/grid-bot/bots-list/BotList.tsx | 21 --- .../grid-bot/bots-list/BotListSkeleton.tsx | 29 --- .../components/grid-bot/bots-list/loading.tsx | 22 --- .../components/grid-bot/bots-list/page.tsx | 27 --- .../create-bot/GridChart/GridChart.tsx | 91 ---------- .../grid-bot/create-bot/GridChart/index.ts | 1 - .../grid-bot/create-bot/GridChart/utils.ts | 17 -- .../AdvancedGridForm/AdvancedGridForm.tsx | 40 ----- .../AdvancedGridForm/AdvancedGridFormItem.tsx | 50 ------ .../AdvancedGridForm/RemoveGridLineButton.tsx | 31 ---- .../fields/GridLinePriceField.tsx | 61 ------- .../fields/GridLineQuantityField.tsx | 67 ------- .../create-bot/form/AdvancedGridForm/index.ts | 1 - .../create-bot/form/CreateGridForm.tsx | 136 -------------- .../grid-bot/create-bot/form/FormTypeTabs.tsx | 83 --------- .../form/SimpleGridForm/SimpleGridForm.tsx | 38 ---- .../SimpleGridForm/fields/GridLevelsField.tsx | 53 ------ .../SimpleGridForm/fields/HighPriceField.tsx | 55 ------ .../SimpleGridForm/fields/LowPriceField.tsx | 54 ------ .../fields/QuantityPerGridField.tsx | 58 ------ .../create-bot/form/SimpleGridForm/index.ts | 1 - .../grid-bot/create-bot/form/SubmitButton.tsx | 49 ----- .../create-bot/form/fields/BotNameField.tsx | 61 ------- .../form/fields/ExchangeAccountField.tsx | 38 ---- .../create-bot/form/fields/FormTypeField.tsx | 74 -------- .../InvestmentField/InvestmentField.tsx | 58 ------ .../InvestmentFieldHelperText.tsx | 36 ---- .../form/fields/InvestmentField/index.ts | 1 - .../create-bot/form/fields/PairField.tsx | 38 ---- .../create-bot/form/helpers/mapFormToDto.ts | 21 --- .../grid-bot/create-bot/form/index.ts | 1 - .../grid-bot/create-bot/hooks/usePagaData.ts | 32 ---- .../grid-bot/create-bot/loading.tsx | 33 ---- .../components/grid-bot/create-bot/page.tsx | 72 -------- .../src/components/login/LoginForm.tsx | 77 -------- apps/frontend/src/hooks/useIsFirstRender.ts | 13 -- apps/frontend/src/hooks/useIsStale.ts | 12 -- apps/frontend/src/lib/react-query/client.ts | 3 - apps/frontend/src/lib/trpc/client.ts | 5 - apps/frontend/src/lib/trpc/getBaseUrl.ts | 28 --- apps/frontend/src/lib/trpc/index.ts | 23 --- apps/frontend/src/lib/trpc/server.ts | 12 -- apps/frontend/src/lib/trpc/types.ts | 7 - apps/frontend/src/providers/StoreProvider.tsx | 13 -- .../providers/ThemeProvider/EmotionCache.tsx | 99 ---------- .../providers/ThemeProvider/ThemeProvider.tsx | 18 -- .../src/providers/ThemeProvider/index.ts | 1 - apps/frontend/src/providers/TrpcProvider.tsx | 82 --------- apps/frontend/src/store/bot-form/actions.ts | 133 -------------- apps/frontend/src/store/bot-form/constants.ts | 6 - apps/frontend/src/store/bot-form/helpers.ts | 6 - apps/frontend/src/store/bot-form/index.ts | 5 - apps/frontend/src/store/bot-form/reducers.ts | 161 ----------------- apps/frontend/src/store/bot-form/selectors.ts | 66 ------- apps/frontend/src/store/bot-form/state.ts | 47 ----- apps/frontend/src/store/bot-form/types.ts | 7 - apps/frontend/src/store/hooks.ts | 6 - apps/frontend/src/store/index.ts | 16 -- apps/frontend/src/theme/index.ts | 93 ---------- apps/frontend/src/types/trpc/bot.ts | 11 -- .../src/types/trpc/exchange-account.ts | 3 - apps/frontend/src/types/trpc/grid-bot.ts | 4 - apps/frontend/src/types/trpc/index.ts | 5 - apps/frontend/src/types/trpc/smart-trade.ts | 3 - apps/frontend/src/types/trpc/symbol.ts | 3 - apps/frontend/src/ui/FlexSpacer.tsx | 11 -- apps/frontend/src/ui/GithubLink.tsx | 17 -- apps/frontend/src/ui/InputSkeleton.tsx | 43 ----- apps/frontend/src/ui/Logo.tsx | 23 --- apps/frontend/src/ui/Main.tsx | 32 ---- .../src/ui/charts/Chart/BaseChart.tsx | 170 ------------------ apps/frontend/src/ui/charts/Chart/Chart.tsx | 29 --- .../frontend/src/ui/charts/Chart/ChartBar.tsx | 22 --- .../src/ui/charts/Chart/ChartContainer.tsx | 18 -- .../charts/Chart/ChartHeader/ChartHeader.tsx | 29 --- .../charts/Chart/ChartHeader/ColorNumber.tsx | 24 --- .../src/ui/charts/Chart/ChartHeader/Ohlc.tsx | 25 --- .../src/ui/charts/Chart/ChartHeader/Price.tsx | 27 --- .../charts/Chart/ChartHeader/PriceChange.tsx | 36 ---- .../ui/charts/Chart/ChartHeader/Symbol.tsx | 21 --- .../ui/charts/Chart/ChartHeader/constants.ts | 1 - .../src/ui/charts/Chart/ChartHeader/index.ts | 3 - .../src/ui/charts/Chart/ChartHeader/types.ts | 1 - .../src/ui/charts/Chart/ChartHeader/utils.ts | 25 --- .../src/ui/charts/Chart/ChartOptions.tsx | 66 ------- .../frontend/src/ui/charts/Chart/constants.ts | 2 - apps/frontend/src/ui/charts/Chart/index.ts | 3 - .../src/ui/charts/Chart/theme/dark.ts | 33 ---- .../src/ui/charts/Chart/theme/light.ts | 33 ---- .../src/ui/charts/Chart/theme/types.ts | 10 -- .../ui/charts/Chart/theme/useChartTheme.ts | 13 -- .../ui/charts/Chart/useCandlesticksChart.ts | 62 ------- .../src/ui/charts/Chart/useExchange.ts | 14 -- apps/frontend/src/ui/charts/Chart/useOHLC.ts | 121 ------------- .../src/ui/charts/Chart/useWatchOHLC.ts | 50 ------ apps/frontend/src/ui/charts/Chart/utils.ts | 31 ---- .../ConfirmationDialog.tsx | 93 ---------- .../ConfirmationDialogProvider.tsx | 54 ------ .../src/ui/confirmation-dialog/context.ts | 94 ---------- .../src/ui/confirmation-dialog/index.ts | 2 - .../useConfirmationDialog.ts | 6 - apps/frontend/src/ui/constants.ts | 2 - .../src/ui/errors/api/TRPCApiErrorModal.tsx | 58 ------ .../ui/errors/api/TRPCApiErrorProvider.tsx | 46 ----- apps/frontend/src/ui/errors/api/context.ts | 18 -- apps/frontend/src/ui/errors/api/index.ts | 3 - .../src/ui/errors/api/useTRPCErrorModal.ts | 6 - .../suspense/TRPCClientErrorBoundary.tsx | 45 ----- .../src/ui/errors/suspense/TRPCErrorSheet.tsx | 51 ------ .../ui/errors/suspense/UnknownErrorSheet.tsx | 31 ---- apps/frontend/src/ui/errors/suspense/index.ts | 1 - apps/frontend/src/ui/errors/types.ts | 7 - .../src/ui/errors/utils/getTrpcErrorValue.ts | 12 -- apps/frontend/src/ui/errors/utils/index.ts | 1 - .../src/ui/errors/utils/isTrpcError.ts | 8 - .../ui/errors/utils/isUnauthorizedError.ts | 10 -- .../src/ui/errors/utils/trpcErrorSchema.ts | 32 ---- apps/frontend/src/ui/icons/CryptoIcon.tsx | 34 ---- apps/frontend/src/ui/icons/ExchangeIcon.tsx | 30 ---- apps/frontend/src/ui/icons/GithubIcon.tsx | 15 -- .../ui/inputs/NumericInput/NumericInput.tsx | 31 ---- .../src/ui/inputs/NumericInput/index.ts | 1 - .../src/ui/inputs/PriceInput/PriceInput.tsx | 45 ----- .../mapPriceFilterToNumericFormatProps.ts | 11 -- .../helpers/validatePriceByFilter.ts | 36 ---- .../src/ui/inputs/PriceInput/index.ts | 1 - .../ui/inputs/QuantityInput/QuantityInput.tsx | 48 ----- .../mapQuantityFilterToNumericFormatProps.ts | 11 -- .../helpers/validateQuantityByFilter.ts | 36 ---- .../src/ui/inputs/QuantityInput/index.ts | 1 - apps/frontend/src/ui/navigation/AppBar.tsx | 34 ---- apps/frontend/src/ui/navigation/AppDrawer.tsx | 57 ------ .../frontend/src/ui/navigation/AppVersion.tsx | 11 -- .../src/ui/navigation/AppVersionInfo.tsx | 36 ---- .../src/ui/navigation/DrawerToggler.tsx | 17 -- .../src/ui/navigation/LeftNavigation.tsx | 34 ---- .../src/ui/navigation/LeftNavigationItem.tsx | 41 ----- .../src/ui/navigation/MobileDrawer.tsx | 29 --- .../src/ui/navigation/ThemeSwitcher.tsx | 32 ---- .../src/ui/navigation/TopNavigation.tsx | 29 --- .../frontend/src/ui/selects/BarSizeSelect.tsx | 36 ---- .../src/ui/selects/ExchangeAccountSelect.tsx | 73 -------- .../selects/SymbolSelect/LisboxComponent.tsx | 106 ----------- .../ui/selects/SymbolSelect/SymbolSelect.tsx | 64 ------- .../src/ui/selects/SymbolSelect/index.ts | 1 - .../ui/selects/SymbolSelect/renderOption.ts | 13 -- .../src/ui/selects/SymbolSelect/types.ts | 9 - apps/frontend/src/ui/snackbar/Snackbar.tsx | 34 ---- .../src/ui/snackbar/SnackbarProvider.tsx | 50 ------ apps/frontend/src/ui/snackbar/context.ts | 48 ----- apps/frontend/src/ui/snackbar/index.ts | 2 - apps/frontend/src/ui/snackbar/useSnackbar.ts | 6 - apps/frontend/src/utils/auth/getAuthToken.ts | 5 - apps/frontend/src/utils/auth/isLoginPage.ts | 5 - .../src/utils/axios/authInterceptor.ts | 10 -- .../bot-name-generator/dictionaries/colors.ts | 54 ------ .../dictionaries/star-wars.ts | 84 --------- .../bot-name-generator/generateBotName.ts | 15 -- .../src/utils/bot-name-generator/index.ts | 1 - apps/frontend/src/utils/charts/barSize.ts | 13 -- apps/frontend/src/utils/charts/index.ts | 2 - apps/frontend/src/utils/charts/marker.ts | 15 -- apps/frontend/src/utils/charts/priceLine.ts | 56 ------ apps/frontend/src/utils/date/formatDateISO.ts | 5 - .../frontend/src/utils/date/formatDateTime.ts | 7 - .../src/utils/date/fromatDateTimeISO.ts | 9 - .../frontend/src/utils/date/startOfYearISO.ts | 8 - apps/frontend/src/utils/date/todayISO.ts | 5 - .../grid-bot/calcAverageQuantityPerGrid.ts | 16 -- .../grid-bot/findHighestGridLinePrice.ts | 7 - .../utils/grid-bot/findLowestGridLinePrice.ts | 7 - .../utils/grid-bot/getWaitingGridLinePrice.ts | 47 ----- .../src/utils/grid-bot/isWaitingGridLine.ts | 19 -- .../waitingPriceFromCurrentAssetPrice.ts | 20 --- apps/frontend/src/utils/mui/createClasses.ts | 100 ----------- apps/frontend/src/utils/mui/index.ts | 1 - .../src/utils/next/createEmotionCache.ts | 5 - apps/frontend/src/utils/next/index.ts | 1 - apps/frontend/src/utils/next/toPage.ts | 44 ----- apps/frontend/src/utils/redux/types.ts | 6 - .../src/utils/rtk/prepareAuthHeaderHandler.ts | 15 -- apps/frontend/src/utils/rtk/setAuthHeader.ts | 3 - .../smart-trades/calcProfitFromSmartTrade.ts | 29 --- .../calcTotalProfitFromSmartTrades.ts | 17 -- apps/frontend/tsconfig.json | 15 -- apps/frontend/types.d.ts | 3 - apps/processor/.env | 1 - apps/processor/.eslintrc.js | 5 - apps/processor/.gitignore | 2 - apps/processor/Dockerfile | 64 ------- apps/processor/README.md | 13 -- apps/processor/package.json | 55 ------ apps/processor/src/index.ts | 61 ------- apps/processor/src/processing/index.ts | 28 --- apps/processor/src/trpc.ts | 45 ----- apps/processor/tsconfig.json | 14 -- apps/processor/webpack.config.js | 43 ----- 296 files changed, 10017 deletions(-) delete mode 120000 apps/frontend/.env delete mode 100644 apps/frontend/.eslintrc.js delete mode 100644 apps/frontend/.gitignore delete mode 100644 apps/frontend/Dockerfile delete mode 100644 apps/frontend/README.md delete mode 100644 apps/frontend/jest.config.js delete mode 100644 apps/frontend/next-env.d.ts delete mode 100644 apps/frontend/next.config.js delete mode 100644 apps/frontend/package.json delete mode 100644 apps/frontend/public/exchanges/logos/64x64/binance.png delete mode 100644 apps/frontend/public/exchanges/logos/64x64/bybit.png delete mode 100644 apps/frontend/public/exchanges/logos/64x64/coinbase.png delete mode 100644 apps/frontend/public/exchanges/logos/64x64/gateio.png delete mode 100644 apps/frontend/public/exchanges/logos/64x64/kraken.png delete mode 100644 apps/frontend/public/exchanges/logos/64x64/okx.png delete mode 100644 apps/frontend/public/favicon.ico delete mode 100644 apps/frontend/public/logo.png delete mode 100644 apps/frontend/public/robots.txt delete mode 100644 apps/frontend/src/app/api/trpc/[trpc]/route.ts delete mode 100644 apps/frontend/src/app/dashboard/accounts/page.tsx delete mode 100644 apps/frontend/src/app/dashboard/bot/[id]/page.tsx delete mode 100644 apps/frontend/src/app/dashboard/bot/info/page.tsx delete mode 100644 apps/frontend/src/app/dashboard/grid-bot/[id]/page.tsx delete mode 100644 apps/frontend/src/app/dashboard/grid-bot/create/page.tsx delete mode 100644 apps/frontend/src/app/dashboard/grid-bot/info/page.tsx delete mode 100644 apps/frontend/src/app/dashboard/grid-bot/page.tsx delete mode 100644 apps/frontend/src/app/dashboard/layout.tsx delete mode 100644 apps/frontend/src/app/dashboard/login/page.tsx delete mode 100644 apps/frontend/src/app/dashboard/page.tsx delete mode 100644 apps/frontend/src/app/layout.tsx delete mode 100644 apps/frontend/src/app/page.tsx delete mode 100644 apps/frontend/src/components/accounts/AccountsListTable/AccountsListTable.tsx delete mode 100644 apps/frontend/src/components/accounts/AccountsListTable/AccountsListTableHead.tsx delete mode 100644 apps/frontend/src/components/accounts/AccountsListTable/AccountsListTableRow.tsx delete mode 100644 apps/frontend/src/components/accounts/AccountsListTable/AccountsListTableToolbar.tsx delete mode 100644 apps/frontend/src/components/accounts/AccountsListTable/index.ts delete mode 100644 apps/frontend/src/components/accounts/CreateAccountDialog/CreateAccountDialog.tsx delete mode 100644 apps/frontend/src/components/accounts/CreateAccountForm/CreateAccountForm.tsx delete mode 100644 apps/frontend/src/components/accounts/CreateAccountForm/UpdateAccountForm.tsx delete mode 100644 apps/frontend/src/components/accounts/CreateAccountForm/fields/AccountIdField.tsx delete mode 100644 apps/frontend/src/components/accounts/CreateAccountForm/fields/AccountNameField.tsx delete mode 100644 apps/frontend/src/components/accounts/CreateAccountForm/fields/ApiKeyField.tsx delete mode 100644 apps/frontend/src/components/accounts/CreateAccountForm/fields/ExchangeCodeField.tsx delete mode 100644 apps/frontend/src/components/accounts/CreateAccountForm/fields/IsDemoAccountField.tsx delete mode 100644 apps/frontend/src/components/accounts/CreateAccountForm/fields/PassphraseField.tsx delete mode 100644 apps/frontend/src/components/accounts/CreateAccountForm/fields/SecretKeyField.tsx delete mode 100644 apps/frontend/src/components/accounts/CreateAccountForm/types.ts delete mode 100644 apps/frontend/src/components/accounts/UpdateAccountDialog/UpdateAccountDialog.tsx delete mode 100644 apps/frontend/src/components/accounts/loading.tsx delete mode 100644 apps/frontend/src/components/accounts/page.tsx delete mode 100644 apps/frontend/src/components/bot/bot-details/BotActions/RunBotTemplateButton.tsx delete mode 100644 apps/frontend/src/components/bot/bot-details/BotChart/BotChart.tsx delete mode 100644 apps/frontend/src/components/bot/bot-details/BotChart/index.ts delete mode 100644 apps/frontend/src/components/bot/bot-details/BotSettings/BotSettings.tsx delete mode 100644 apps/frontend/src/components/bot/bot-details/BotSettings/BotSettingsCard.tsx delete mode 100644 apps/frontend/src/components/bot/bot-details/BotSettings/index.ts delete mode 100644 apps/frontend/src/components/bot/bot-details/BotSettingsForm/BotSettingsForm.tsx delete mode 100644 apps/frontend/src/components/bot/bot-details/loading.tsx delete mode 100644 apps/frontend/src/components/bot/bot-details/page.tsx delete mode 100644 apps/frontend/src/components/common/bot/BotStatusSwitcher.tsx delete mode 100644 apps/frontend/src/components/common/bot/actions/BotActions.tsx delete mode 100644 apps/frontend/src/components/common/bot/actions/BotAdditionalActions.tsx delete mode 100644 apps/frontend/src/components/common/bot/actions/buttons/CronPlacePendingOrderButton.tsx delete mode 100644 apps/frontend/src/components/common/bot/actions/buttons/DeleteBotButton.tsx delete mode 100644 apps/frontend/src/components/common/bot/actions/buttons/RunBotTemplateButton.tsx delete mode 100644 apps/frontend/src/components/common/bot/actions/buttons/StartStopBotButton.tsx delete mode 100644 apps/frontend/src/components/common/bot/actions/buttons/SyncOrdersButton.tsx delete mode 100644 apps/frontend/src/components/common/bot/settings/PairSettingListItem.tsx delete mode 100644 apps/frontend/src/components/common/bot/settings/SettingListItem.tsx delete mode 100644 apps/frontend/src/components/common/bot/settings/StatusSettingListItem.tsx delete mode 100644 apps/frontend/src/components/common/smart-trades/ProfitsCard/Profit.tsx delete mode 100644 apps/frontend/src/components/common/smart-trades/ProfitsCard/ProfitDetails.tsx delete mode 100644 apps/frontend/src/components/common/smart-trades/ProfitsCard/ProfitItem.tsx delete mode 100644 apps/frontend/src/components/common/smart-trades/ProfitsCard/ProfitsCard.tsx delete mode 100644 apps/frontend/src/components/common/smart-trades/ProfitsCard/index.ts delete mode 100644 apps/frontend/src/components/common/smart-trades/SmartTradesTable/NoActiveSmartTradesPlaceholder.tsx delete mode 100644 apps/frontend/src/components/common/smart-trades/SmartTradesTable/SmartTradeStatus.tsx delete mode 100644 apps/frontend/src/components/common/smart-trades/SmartTradesTable/SmartTradesTable.tsx delete mode 100644 apps/frontend/src/components/common/smart-trades/SmartTradesTable/SmartTradesTableHead.tsx delete mode 100644 apps/frontend/src/components/common/smart-trades/SmartTradesTable/SmartTradesTableItem.tsx delete mode 100644 apps/frontend/src/components/common/smart-trades/SmartTradesTable/constants.ts delete mode 100644 apps/frontend/src/components/common/smart-trades/SmartTradesTable/index.ts delete mode 100644 apps/frontend/src/components/debug/SyncClosedOrdersButton.tsx delete mode 100644 apps/frontend/src/components/grid-bot/bot-details/BotSettings/BotSettings.tsx delete mode 100644 apps/frontend/src/components/grid-bot/bot-details/BotSettings/BotSettingsCard.tsx delete mode 100644 apps/frontend/src/components/grid-bot/bot-details/BotSettings/index.ts delete mode 100644 apps/frontend/src/components/grid-bot/bot-details/GridBotSettings/GridBotSettings.tsx delete mode 100644 apps/frontend/src/components/grid-bot/bot-details/GridBotSettings/SettingInput.tsx delete mode 100644 apps/frontend/src/components/grid-bot/bot-details/GridBotSettings/index.ts delete mode 100644 apps/frontend/src/components/grid-bot/bot-details/GridDetailChart/GridDetailChart.tsx delete mode 100644 apps/frontend/src/components/grid-bot/bot-details/GridDetailChart/index.ts delete mode 100644 apps/frontend/src/components/grid-bot/bot-details/GridDetailChart/utils/computePriceLines.ts delete mode 100644 apps/frontend/src/components/grid-bot/bot-details/GridDetailChart/utils/computeTradeMarkers.ts delete mode 100644 apps/frontend/src/components/grid-bot/bot-details/loading.tsx delete mode 100644 apps/frontend/src/components/grid-bot/bot-details/page.tsx delete mode 100644 apps/frontend/src/components/grid-bot/bots-list/BotCard/BotCard.tsx delete mode 100644 apps/frontend/src/components/grid-bot/bots-list/BotCard/BotStatusIndicator.tsx delete mode 100644 apps/frontend/src/components/grid-bot/bots-list/BotCard/Bull.tsx delete mode 100644 apps/frontend/src/components/grid-bot/bots-list/BotCard/index.ts delete mode 100644 apps/frontend/src/components/grid-bot/bots-list/BotList.tsx delete mode 100644 apps/frontend/src/components/grid-bot/bots-list/BotListSkeleton.tsx delete mode 100644 apps/frontend/src/components/grid-bot/bots-list/loading.tsx delete mode 100644 apps/frontend/src/components/grid-bot/bots-list/page.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/GridChart/GridChart.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/GridChart/index.ts delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/GridChart/utils.ts delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/AdvancedGridForm.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/AdvancedGridFormItem.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/RemoveGridLineButton.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/fields/GridLinePriceField.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/fields/GridLineQuantityField.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/index.ts delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/CreateGridForm.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/FormTypeTabs.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/SimpleGridForm.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/fields/GridLevelsField.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/fields/HighPriceField.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/fields/LowPriceField.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/fields/QuantityPerGridField.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/index.ts delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/SubmitButton.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/fields/BotNameField.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/fields/ExchangeAccountField.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/fields/FormTypeField.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/fields/InvestmentField/InvestmentField.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/fields/InvestmentField/InvestmentFieldHelperText.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/fields/InvestmentField/index.ts delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/fields/PairField.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/helpers/mapFormToDto.ts delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/form/index.ts delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/hooks/usePagaData.ts delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/loading.tsx delete mode 100644 apps/frontend/src/components/grid-bot/create-bot/page.tsx delete mode 100644 apps/frontend/src/components/login/LoginForm.tsx delete mode 100644 apps/frontend/src/hooks/useIsFirstRender.ts delete mode 100644 apps/frontend/src/hooks/useIsStale.ts delete mode 100644 apps/frontend/src/lib/react-query/client.ts delete mode 100644 apps/frontend/src/lib/trpc/client.ts delete mode 100644 apps/frontend/src/lib/trpc/getBaseUrl.ts delete mode 100644 apps/frontend/src/lib/trpc/index.ts delete mode 100644 apps/frontend/src/lib/trpc/server.ts delete mode 100644 apps/frontend/src/lib/trpc/types.ts delete mode 100644 apps/frontend/src/providers/StoreProvider.tsx delete mode 100644 apps/frontend/src/providers/ThemeProvider/EmotionCache.tsx delete mode 100644 apps/frontend/src/providers/ThemeProvider/ThemeProvider.tsx delete mode 100644 apps/frontend/src/providers/ThemeProvider/index.ts delete mode 100644 apps/frontend/src/providers/TrpcProvider.tsx delete mode 100644 apps/frontend/src/store/bot-form/actions.ts delete mode 100644 apps/frontend/src/store/bot-form/constants.ts delete mode 100644 apps/frontend/src/store/bot-form/helpers.ts delete mode 100644 apps/frontend/src/store/bot-form/index.ts delete mode 100644 apps/frontend/src/store/bot-form/reducers.ts delete mode 100644 apps/frontend/src/store/bot-form/selectors.ts delete mode 100644 apps/frontend/src/store/bot-form/state.ts delete mode 100644 apps/frontend/src/store/bot-form/types.ts delete mode 100644 apps/frontend/src/store/hooks.ts delete mode 100644 apps/frontend/src/store/index.ts delete mode 100644 apps/frontend/src/theme/index.ts delete mode 100644 apps/frontend/src/types/trpc/bot.ts delete mode 100644 apps/frontend/src/types/trpc/exchange-account.ts delete mode 100644 apps/frontend/src/types/trpc/grid-bot.ts delete mode 100644 apps/frontend/src/types/trpc/index.ts delete mode 100644 apps/frontend/src/types/trpc/smart-trade.ts delete mode 100644 apps/frontend/src/types/trpc/symbol.ts delete mode 100644 apps/frontend/src/ui/FlexSpacer.tsx delete mode 100644 apps/frontend/src/ui/GithubLink.tsx delete mode 100644 apps/frontend/src/ui/InputSkeleton.tsx delete mode 100644 apps/frontend/src/ui/Logo.tsx delete mode 100644 apps/frontend/src/ui/Main.tsx delete mode 100644 apps/frontend/src/ui/charts/Chart/BaseChart.tsx delete mode 100644 apps/frontend/src/ui/charts/Chart/Chart.tsx delete mode 100644 apps/frontend/src/ui/charts/Chart/ChartBar.tsx delete mode 100644 apps/frontend/src/ui/charts/Chart/ChartContainer.tsx delete mode 100644 apps/frontend/src/ui/charts/Chart/ChartHeader/ChartHeader.tsx delete mode 100644 apps/frontend/src/ui/charts/Chart/ChartHeader/ColorNumber.tsx delete mode 100644 apps/frontend/src/ui/charts/Chart/ChartHeader/Ohlc.tsx delete mode 100644 apps/frontend/src/ui/charts/Chart/ChartHeader/Price.tsx delete mode 100644 apps/frontend/src/ui/charts/Chart/ChartHeader/PriceChange.tsx delete mode 100644 apps/frontend/src/ui/charts/Chart/ChartHeader/Symbol.tsx delete mode 100644 apps/frontend/src/ui/charts/Chart/ChartHeader/constants.ts delete mode 100644 apps/frontend/src/ui/charts/Chart/ChartHeader/index.ts delete mode 100644 apps/frontend/src/ui/charts/Chart/ChartHeader/types.ts delete mode 100644 apps/frontend/src/ui/charts/Chart/ChartHeader/utils.ts delete mode 100644 apps/frontend/src/ui/charts/Chart/ChartOptions.tsx delete mode 100644 apps/frontend/src/ui/charts/Chart/constants.ts delete mode 100644 apps/frontend/src/ui/charts/Chart/index.ts delete mode 100644 apps/frontend/src/ui/charts/Chart/theme/dark.ts delete mode 100644 apps/frontend/src/ui/charts/Chart/theme/light.ts delete mode 100644 apps/frontend/src/ui/charts/Chart/theme/types.ts delete mode 100644 apps/frontend/src/ui/charts/Chart/theme/useChartTheme.ts delete mode 100644 apps/frontend/src/ui/charts/Chart/useCandlesticksChart.ts delete mode 100644 apps/frontend/src/ui/charts/Chart/useExchange.ts delete mode 100644 apps/frontend/src/ui/charts/Chart/useOHLC.ts delete mode 100644 apps/frontend/src/ui/charts/Chart/useWatchOHLC.ts delete mode 100644 apps/frontend/src/ui/charts/Chart/utils.ts delete mode 100644 apps/frontend/src/ui/confirmation-dialog/ConfirmationDialog.tsx delete mode 100644 apps/frontend/src/ui/confirmation-dialog/ConfirmationDialogProvider.tsx delete mode 100644 apps/frontend/src/ui/confirmation-dialog/context.ts delete mode 100644 apps/frontend/src/ui/confirmation-dialog/index.ts delete mode 100644 apps/frontend/src/ui/confirmation-dialog/useConfirmationDialog.ts delete mode 100644 apps/frontend/src/ui/constants.ts delete mode 100644 apps/frontend/src/ui/errors/api/TRPCApiErrorModal.tsx delete mode 100644 apps/frontend/src/ui/errors/api/TRPCApiErrorProvider.tsx delete mode 100644 apps/frontend/src/ui/errors/api/context.ts delete mode 100644 apps/frontend/src/ui/errors/api/index.ts delete mode 100644 apps/frontend/src/ui/errors/api/useTRPCErrorModal.ts delete mode 100644 apps/frontend/src/ui/errors/suspense/TRPCClientErrorBoundary.tsx delete mode 100644 apps/frontend/src/ui/errors/suspense/TRPCErrorSheet.tsx delete mode 100644 apps/frontend/src/ui/errors/suspense/UnknownErrorSheet.tsx delete mode 100644 apps/frontend/src/ui/errors/suspense/index.ts delete mode 100644 apps/frontend/src/ui/errors/types.ts delete mode 100644 apps/frontend/src/ui/errors/utils/getTrpcErrorValue.ts delete mode 100644 apps/frontend/src/ui/errors/utils/index.ts delete mode 100644 apps/frontend/src/ui/errors/utils/isTrpcError.ts delete mode 100644 apps/frontend/src/ui/errors/utils/isUnauthorizedError.ts delete mode 100644 apps/frontend/src/ui/errors/utils/trpcErrorSchema.ts delete mode 100644 apps/frontend/src/ui/icons/CryptoIcon.tsx delete mode 100644 apps/frontend/src/ui/icons/ExchangeIcon.tsx delete mode 100644 apps/frontend/src/ui/icons/GithubIcon.tsx delete mode 100644 apps/frontend/src/ui/inputs/NumericInput/NumericInput.tsx delete mode 100644 apps/frontend/src/ui/inputs/NumericInput/index.ts delete mode 100644 apps/frontend/src/ui/inputs/PriceInput/PriceInput.tsx delete mode 100644 apps/frontend/src/ui/inputs/PriceInput/helpers/mapPriceFilterToNumericFormatProps.ts delete mode 100644 apps/frontend/src/ui/inputs/PriceInput/helpers/validatePriceByFilter.ts delete mode 100644 apps/frontend/src/ui/inputs/PriceInput/index.ts delete mode 100644 apps/frontend/src/ui/inputs/QuantityInput/QuantityInput.tsx delete mode 100644 apps/frontend/src/ui/inputs/QuantityInput/helpers/mapQuantityFilterToNumericFormatProps.ts delete mode 100644 apps/frontend/src/ui/inputs/QuantityInput/helpers/validateQuantityByFilter.ts delete mode 100644 apps/frontend/src/ui/inputs/QuantityInput/index.ts delete mode 100644 apps/frontend/src/ui/navigation/AppBar.tsx delete mode 100644 apps/frontend/src/ui/navigation/AppDrawer.tsx delete mode 100644 apps/frontend/src/ui/navigation/AppVersion.tsx delete mode 100644 apps/frontend/src/ui/navigation/AppVersionInfo.tsx delete mode 100644 apps/frontend/src/ui/navigation/DrawerToggler.tsx delete mode 100644 apps/frontend/src/ui/navigation/LeftNavigation.tsx delete mode 100644 apps/frontend/src/ui/navigation/LeftNavigationItem.tsx delete mode 100644 apps/frontend/src/ui/navigation/MobileDrawer.tsx delete mode 100644 apps/frontend/src/ui/navigation/ThemeSwitcher.tsx delete mode 100644 apps/frontend/src/ui/navigation/TopNavigation.tsx delete mode 100644 apps/frontend/src/ui/selects/BarSizeSelect.tsx delete mode 100644 apps/frontend/src/ui/selects/ExchangeAccountSelect.tsx delete mode 100644 apps/frontend/src/ui/selects/SymbolSelect/LisboxComponent.tsx delete mode 100644 apps/frontend/src/ui/selects/SymbolSelect/SymbolSelect.tsx delete mode 100644 apps/frontend/src/ui/selects/SymbolSelect/index.ts delete mode 100644 apps/frontend/src/ui/selects/SymbolSelect/renderOption.ts delete mode 100644 apps/frontend/src/ui/selects/SymbolSelect/types.ts delete mode 100644 apps/frontend/src/ui/snackbar/Snackbar.tsx delete mode 100644 apps/frontend/src/ui/snackbar/SnackbarProvider.tsx delete mode 100644 apps/frontend/src/ui/snackbar/context.ts delete mode 100644 apps/frontend/src/ui/snackbar/index.ts delete mode 100644 apps/frontend/src/ui/snackbar/useSnackbar.ts delete mode 100644 apps/frontend/src/utils/auth/getAuthToken.ts delete mode 100644 apps/frontend/src/utils/auth/isLoginPage.ts delete mode 100644 apps/frontend/src/utils/axios/authInterceptor.ts delete mode 100644 apps/frontend/src/utils/bot-name-generator/dictionaries/colors.ts delete mode 100644 apps/frontend/src/utils/bot-name-generator/dictionaries/star-wars.ts delete mode 100644 apps/frontend/src/utils/bot-name-generator/generateBotName.ts delete mode 100644 apps/frontend/src/utils/bot-name-generator/index.ts delete mode 100644 apps/frontend/src/utils/charts/barSize.ts delete mode 100644 apps/frontend/src/utils/charts/index.ts delete mode 100644 apps/frontend/src/utils/charts/marker.ts delete mode 100644 apps/frontend/src/utils/charts/priceLine.ts delete mode 100644 apps/frontend/src/utils/date/formatDateISO.ts delete mode 100644 apps/frontend/src/utils/date/formatDateTime.ts delete mode 100644 apps/frontend/src/utils/date/fromatDateTimeISO.ts delete mode 100644 apps/frontend/src/utils/date/startOfYearISO.ts delete mode 100644 apps/frontend/src/utils/date/todayISO.ts delete mode 100644 apps/frontend/src/utils/grid-bot/calcAverageQuantityPerGrid.ts delete mode 100644 apps/frontend/src/utils/grid-bot/findHighestGridLinePrice.ts delete mode 100644 apps/frontend/src/utils/grid-bot/findLowestGridLinePrice.ts delete mode 100644 apps/frontend/src/utils/grid-bot/getWaitingGridLinePrice.ts delete mode 100644 apps/frontend/src/utils/grid-bot/isWaitingGridLine.ts delete mode 100644 apps/frontend/src/utils/grid-bot/waitingPriceFromCurrentAssetPrice.ts delete mode 100644 apps/frontend/src/utils/mui/createClasses.ts delete mode 100644 apps/frontend/src/utils/mui/index.ts delete mode 100644 apps/frontend/src/utils/next/createEmotionCache.ts delete mode 100644 apps/frontend/src/utils/next/index.ts delete mode 100644 apps/frontend/src/utils/next/toPage.ts delete mode 100644 apps/frontend/src/utils/redux/types.ts delete mode 100644 apps/frontend/src/utils/rtk/prepareAuthHeaderHandler.ts delete mode 100644 apps/frontend/src/utils/rtk/setAuthHeader.ts delete mode 100644 apps/frontend/src/utils/smart-trades/calcProfitFromSmartTrade.ts delete mode 100644 apps/frontend/src/utils/smart-trades/calcTotalProfitFromSmartTrades.ts delete mode 100644 apps/frontend/tsconfig.json delete mode 100644 apps/frontend/types.d.ts delete mode 120000 apps/processor/.env delete mode 100644 apps/processor/.eslintrc.js delete mode 100644 apps/processor/.gitignore delete mode 100644 apps/processor/Dockerfile delete mode 100644 apps/processor/README.md delete mode 100644 apps/processor/package.json delete mode 100644 apps/processor/src/index.ts delete mode 100644 apps/processor/src/processing/index.ts delete mode 100644 apps/processor/src/trpc.ts delete mode 100644 apps/processor/tsconfig.json delete mode 100644 apps/processor/webpack.config.js diff --git a/apps/frontend/.env b/apps/frontend/.env deleted file mode 120000 index c7360fb8..00000000 --- a/apps/frontend/.env +++ /dev/null @@ -1 +0,0 @@ -../../.env \ No newline at end of file diff --git a/apps/frontend/.eslintrc.js b/apps/frontend/.eslintrc.js deleted file mode 100644 index 0eec699b..00000000 --- a/apps/frontend/.eslintrc.js +++ /dev/null @@ -1,5 +0,0 @@ -/** @type {import("eslint").Linter.Config} */ -module.exports = { - root: true, - extends: ["@opentrader/eslint-config/next.js"], -}; diff --git a/apps/frontend/.gitignore b/apps/frontend/.gitignore deleted file mode 100644 index 050841de..00000000 --- a/apps/frontend/.gitignore +++ /dev/null @@ -1,40 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env.local -.env.development.local -.env.test.local -.env.production.local - -# vercel -.vercel - -# typescript -*.tsbuildinfo - -# coingecko -src/lib/coingecko/client diff --git a/apps/frontend/Dockerfile b/apps/frontend/Dockerfile deleted file mode 100644 index 763e7c24..00000000 --- a/apps/frontend/Dockerfile +++ /dev/null @@ -1,80 +0,0 @@ -FROM node:18-alpine AS base - -# The web Dockerfile is copy-pasted into our main docs at /docs/handbook/deploying-with-docker. -# Make sure you update this Dockerfile, the Dockerfile in the web workspace and copy that over to Dockerfile in the docs. - -FROM base AS builder -# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. -RUN apk add --no-cache libc6-compat -RUN apk update -# Install pnpm -ENV PNPM_HOME="/pnpm" -ENV PATH="$PNPM_HOME:$PATH" -RUN corepack enable -# Set working directory -WORKDIR /app -RUN pnpm add turbo -g -COPY . . -RUN turbo prune frontend --docker - -# Add lockfile and package.json's of isolated subworkspace -FROM base AS installer -RUN apk add --no-cache libc6-compat -RUN apk update -WORKDIR /app - -# Install pnpm & turbo -ENV PNPM_HOME="/pnpm" -ENV PATH="$PNPM_HOME:$PATH" -RUN corepack enable -RUN pnpm add turbo -g - -# First install dependencies (as they change less often) -COPY .gitignore .gitignore -COPY --from=builder /app/out/json/ . -# Copy Prisma Schema as it is not included in `/json` dir -COPY --from=builder /app/out/full/packages/prisma/src/schema.prisma ./packages/prisma/src/schema.prisma -RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store pnpm fetch -RUN pnpm install --offline - -# Build the project and its dependencies -COPY --from=builder /app/out/full/ . -COPY turbo.json turbo.json - -# Uncomment and use build args to enable remote caching -# ARG TURBO_TEAM -# ENV TURBO_TEAM=$TURBO_TEAM - -# ARG TURBO_TOKEN -# ENV TURBO_TOKEN=$TURBO_TOKEN - -ARG DATABASE_URL -ENV DATABASE_URL=$DATABASE_URL - -ARG NEXT_PUBLIC_PROCESSOR_URL -ENV NEXT_PUBLIC_PROCESSOR_URL=$NEXT_PUBLIC_PROCESSOR_URL - -ARG NEXT_PUBLIC_PROCESSOR_ENABLE_TRPC -ENV NEXT_PUBLIC_PROCESSOR_ENABLE_TRPC=$NEXT_PUBLIC_PROCESSOR_ENABLE_TRPC - -RUN turbo run prisma:deploy --filter=./packages/prisma -RUN turbo run build --filter=frontend - -FROM base AS runner -WORKDIR /app - -# Don't run production as root -RUN addgroup --system --gid 1001 nodejs -RUN adduser --system --uid 1001 nextjs -USER nextjs - -COPY --from=installer /app/apps/frontend/next.config.js . -COPY --from=installer /app/apps/frontend/package.json . - -# Automatically leverage output traces to reduce image size -# https://nextjs.org/docs/advanced-features/output-file-tracing -COPY --from=installer --chown=nextjs:nodejs /app/apps/frontend/.next/standalone ./ -COPY --from=installer --chown=nextjs:nodejs /app/apps/frontend/.next/static ./apps/frontend/.next/static -COPY --from=installer --chown=nextjs:nodejs /app/apps/frontend/public ./apps/frontend/public - -CMD node apps/frontend/server.js diff --git a/apps/frontend/README.md b/apps/frontend/README.md deleted file mode 100644 index 91909466..00000000 --- a/apps/frontend/README.md +++ /dev/null @@ -1,21 +0,0 @@ -This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). - -## Getting Started - -First, run the development server: - -```bash -$ cp .env.sample .env -$ npm run bootstrap - -$ npm run dev -``` - -## Coingecko Developer API - -- Swagger: https://www.coingecko.com/en/api/documentation -- Unofficial Swagger (better types): https://app.swaggerhub.com/apis/starksm64/CoinGecko/3.0 - -## CoinMarketCap Developer API - -- Swagger: https://pro-api.coinmarketcap.com/swagger.json diff --git a/apps/frontend/jest.config.js b/apps/frontend/jest.config.js deleted file mode 100644 index 85467739..00000000 --- a/apps/frontend/jest.config.js +++ /dev/null @@ -1,29 +0,0 @@ -// jest.config.js -const nextJest = require('next/jest') - -const createJestConfig = nextJest({ - // Provide the path to your Next.js app to load next.config.js and .env files in your test environment - dir: './', -}) - -// Add any custom config to be passed to Jest -/** @type {import('jest').Config} */ -const customJestConfig = { - // Add more setup options before each test is run - // setupFilesAfterEnv: ['/jest.setup.js'], - // if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work - moduleDirectories: ['node_modules', '/'], - - // If you're using [Module Path Aliases](https://nextjs.org/docs/advanced-features/module-path-aliases), - // you will have to add the moduleNameMapper in order for jest to resolve your absolute paths. - // The paths have to be matching with the paths option within the compilerOptions in the tsconfig.json - // For example: - - moduleNameMapper: { - '@/(.*)$': '/src/$1', - }, - testEnvironment: 'jest-environment-jsdom', -} - -// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async -module.exports = createJestConfig(customJestConfig) diff --git a/apps/frontend/next-env.d.ts b/apps/frontend/next-env.d.ts deleted file mode 100644 index 4f11a03d..00000000 --- a/apps/frontend/next-env.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -/// -/// - -// NOTE: This file should not be edited -// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/apps/frontend/next.config.js b/apps/frontend/next.config.js deleted file mode 100644 index a88b100e..00000000 --- a/apps/frontend/next.config.js +++ /dev/null @@ -1,30 +0,0 @@ -const { z } = require("zod"); - -const envValidationSchema = z.object({ - NEXT_PUBLIC_PROCESSOR_URL: z.string().optional(), - NEXT_PUBLIC_PROCESSOR_ENABLE_TRPC: z.enum(["true", ""]).optional(), - NEXT_PUBLIC_STATIC: z.enum(["true", ""]).optional(), - DATABASE_URL: z.string().min(1), - ADMIN_PASSWORD: z.string().min(1), -}); -envValidationSchema.parse(process.env); // validate ENV schema - -/** @type {import('next').NextConfig} */ -module.exports = { - output: process.env.NEXT_PUBLIC_STATIC === "true" ? "export" : "standalone", - reactStrictMode: true, - webpack: (config) => { - // Solves: Module not found: `bufferutil` and `utf-8-validate` - // when importing `ccxt` in a Server Component (#57) - config.externals.push({ - "utf-8-validate": "commonjs utf-8-validate", - bufferutil: "commonjs bufferutil", - }); - - return config; - }, - experimental: { - optimizePackageImports: ["@mui/base", "@mui/joy"], - missingSuspenseWithCSRBailout: false, // error when building app: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout - }, -}; diff --git a/apps/frontend/package.json b/apps/frontend/package.json deleted file mode 100644 index 3430eea8..00000000 --- a/apps/frontend/package.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "name": "frontend", - "version": "0.0.1", - "scripts": { - "dev": "next dev", - "build": "next build", - "build:static": "NEXT_PUBLIC_STATIC=true next build", - "start": "next start", - "start:prod": "next start", - "lint": "eslint . --quiet", - "lint:fix": "eslint . --fix", - "test:unit": "jest" - }, - "dependencies": { - "@emotion/cache": "^11.11.0", - "@emotion/react": "^11.11.4", - "@emotion/server": "^11.11.0", - "@emotion/styled": "^11.11.5", - "@mui/base": "5.0.0-beta.40", - "@mui/icons-material": "^5.15.17", - "@mui/joy": "5.0.0-beta.36", - "@opentrader/exchanges": "workspace:*", - "@opentrader/tools": "workspace:*", - "@opentrader/trpc": "workspace:*", - "@reduxjs/toolkit": "^1.9.7", - "@tanstack/react-query": "^4.36.1", - "@trpc/client": "^10.45.2", - "@trpc/react-query": "^10.45.2", - "@trpc/server": "^10.45.2", - "axios": "^1.6.8", - "big.js": "^6.2.1", - "ccxt": "4.3.27", - "clsx": "^2.1.1", - "date-fns": "^2.30.0", - "final-form": "^4.20.10", - "lightweight-charts": "^4.1.4", - "lodash": "^4.17.21", - "next": "14.2.3", - "react": "18.3.1", - "react-dom": "18.3.1", - "react-final-form": "^6.5.9", - "react-number-format": "^5.3.4", - "react-redux": "^8.1.3", - "react-window": "^1.8.10", - "redux": "^4.2.1", - "server-only": "^0.0.1", - "superjson": "^1.13.3", - "usehooks-ts": "^2.16.0", - "zod": "3.22.4" - }, - "devDependencies": { - "@next/eslint-plugin-next": "^14.2.3", - "@opentrader/eslint-config": "workspace:*", - "@opentrader/tsconfig": "workspace:*", - "@opentrader/types": "workspace:*", - "@types/big.js": "^6.2.2", - "@types/eslint": "^8.56.10", - "@types/jest": "^29.5.12", - "@types/lodash": "^4.17.1", - "@types/node": "^20.12.11", - "@types/react": "18.3.1", - "@types/react-window": "^1.8.8", - "eslint": "8.54.0", - "jest": "^29.7.0", - "jest-environment-jsdom": "^29.7.0", - "typescript": "^5.2.2" - }, - "husky": { - "hooks": { - "pre-commit": "lint-staged" - } - }, - "lint-staged": { - "*.{js,ts,tsx}": [ - "eslint --fix" - ] - } -} diff --git a/apps/frontend/public/exchanges/logos/64x64/binance.png b/apps/frontend/public/exchanges/logos/64x64/binance.png deleted file mode 100644 index f606e247dd7faf6f59df6bc01e049fcaa33974f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2050 zcmXw32~bm47f#qjwtxactg^@mW_b&X;#Lq)^cRt$xKkr5_E z)<7C=qD*t4AqM$NI|Mf1OzgU!fQ7kBMPA%pHPJ?uHIlLuT>(50*iz`N;Ua^-dy5&K3Kp#7K=Y6~QLO;QM5~3B%R!*< z9#z4CWx$~W0S-Web$K_JxiJ_qQ$keL4o$M*&n+n6XQ~@egn$BPc<9Gg%2yr&V7z4d zOtB%18vsmNKCI;-fIV3w1;CIqNka^Zj7b@8qyX5HY$|{^$)bYNCfM*~8$8hl^Rk2F zz=25~ZKiyBL>+6TjJ8n6A5v;!-BcVZNd1OE8f_-a8p%K}W02)cvgR>-d8?Pane@30 zdQB(KbRe1zM8Sf-u*jfl8G{7cG}DO=H<7hMWD=0ZB3&==)OMn3E(}aMKCJ6P#~=79 zxquKDv;*j;A4357*AC=4gQOQAS^=Ws`hb!_u{u7YWCae^d24#$Ssr*14WNic8fk@Q z_{c0D^v(xB(saP@9|2pMS$B44b_7Zc47%$yK40OtDx)EwB@iOx^p zfBmpNf1?n^r2d%1f36F~y3skIuh8{=1sLVQGtrT|aCn31oQbI(Z-zJ3n>y-E2n2&( z;^^Gxq&F9thzR=h5_7$YG&L>dlF=v<5uWt*>7~CAdV8D~OB|gp7Uk(mPZGR$cCm6yK1aL_XCT*~F#g8ZC}1+={6Nna^GN`WEYSl10R&FJCTQzfyD(uF%{EjXO%)V8oqyY~t2 z?H!L@y2-w}T*{5I^oUA2UTcxE>g@URFj)V8cyBIU2+erpd*9 z;yzr0vfx}&yT!zjudNAr7Y44i)w$+A2q{hz;OT4q{fnE&?dDDvSDdIC_*rx9?BE4V zQB4g#oRlkw&;O)2QqpVlR_!aaap75^8xjjDt`QUX+LekV^PK_j0=j}#wZy}5^m;jV z&SxU8{^s*$L5Q;d@Q>oCz0lo?oRRO6h#L~=D+cooy6M3YWntm(PUar`uf2P_Nkf{!ZcTI0L9Yb7;VCNH9(uyid&Z4CVLV$P z=UEAMSqvB1$p>{(_jQDta&y~QQnazgiBZ|_V#W?xTL1CRrI3B77hSjPWOkiLa$TqU zt?%R9>#XY{(@~3(nkUNJbVPj1#?g(AA2{k$c9HNZYcr2d+2@gb>_(fv}Z%Z8p zcH}3neh8acOm7Y`BYldud2O=sCHL5P;-ha{4DCNT-MwP&L zfwNsPA&^n!KvvGB-U!M)BN43aSvVfQKgyDxgjV#^ztXSc6^i@cS_I-ERz=6~( zw#C8d&Rq+a2dQ={C!E5|PdOc_4qxRFIH&lG){dTjW_IR!U@QJW{I03kYm2>i?yhDz z2x*q48@B{tMz^u2gIAQlR%WiZzU$?9KKyC+#+-`*CGJ{7vd_wGYHDb$VT5B?uVDyn z-bB{;S4ONUO&xvmuzTUs->RnTPwOAui=q1L6+2$teSy8bZadNVorXwg4l%uKMold72^%+;F&Un*dH{U=&Zz2^x$&9nGM?7nzSMkikO1p$W{HLese zaGA<9;N$-DZP@;N`R_lfd=3}2`MC{zgRLZg-?TYz^J|;5{bwCz?gMvoqD+{14u5zY za^7v5_`>J5GLu*z_?hX>^8ausr|c2GR6X~m^h$TLiF!;E&ZM9JTwL7&l2*oIS|-<&XZuMub5v@*l?cro8gGl#EB)6cE$ED>x7sZ;)a zS$yTY*z2ZWW7$vqd$>bNVcyZ|`|As^==k`8x ztGSqEbdF`kGoJ7=vsuzLntn&~nddzHB-bj%=diGiIbg*@29Yca27KHT>_1pEKg?ce T%;}sA40{GoS3j3^P6HX% diff --git a/apps/frontend/public/exchanges/logos/64x64/coinbase.png b/apps/frontend/public/exchanges/logos/64x64/coinbase.png deleted file mode 100644 index 1d5f59cf533eeabdb9b32e1e661f6b4f3a5ea57a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 520 zcmV+j0{8uiP)HIkMz2lFK6lD*GUR+8M znI2xqY6_Ness{IVDM!|hXDP4MpwX_KQ^3J`I}8po+ODvC7Q?xe_o{R@&tEf!z@pi8 zh2dFrfuY$nk>Q!&@?73{t#%leRTT`$t_U99i_P%hUTlJgyxoHPy}e7+uR1Nv@$t%< zU+T>^y?3ewb7zC%(u9d2gdsrM8O`572KdT8un?84-JI9IzM~^d$K;m?AQ1M zKhW44_G@$t8wKZ(>JqX#3eKUiTF^KO&Y`hdkUAR9BehzPnjT(AYI=Afsp;W`q^5@# zlA0b~NNRd`A*rL`JW{I#jicZk8mk43qu?AGU4llzIi$J;t@eif8e_sb!G4XdVXM7h zuh#g`0NAIsf*UMG!5)hh-fww&!+eWNd1U-I+-TJc=34!i^^Zet_D~CRJY32PYyQFm z-fqGD-ZsHQd$AcF+>0W3IJ+tsl2tYPcv145*OI}&Y`VbEEV{z**$pAXcY^tuZ-J$= z*cFzKb{HI_w^I=HEAqZqjxiqZw@q*PR8Fj&6Ao@QJ-pDCo%jS(H~vczi1|hU0000< KMNUMnLSTaK?e+lx diff --git a/apps/frontend/public/exchanges/logos/64x64/gateio.png b/apps/frontend/public/exchanges/logos/64x64/gateio.png deleted file mode 100644 index 103dc146603618cfa2f3d3625e24859eb21ce933..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2212 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 diff --git a/apps/frontend/public/favicon.ico b/apps/frontend/public/favicon.ico deleted file mode 100644 index e0925e7f44e9c3c9bb10dc0f97764db0bd7c3114..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13641 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 bq_6)Euudbo`&v^(00000NkvXXu0mjf9b&`j diff --git a/apps/frontend/public/logo.png b/apps/frontend/public/logo.png deleted file mode 100644 index a48d04462423f109d386d96a5f6ad52e9464df92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24642 zcmXtAbySn@-`?nM0YMt18A?hcASr@$gOqfKNH?OSbSvFCN*JY}NJx!Nkr<;Jw!P2y zch36rN+RdL{0S$U zEy6lCIz^$8P@ViI@<;8`ipxb8!gA2G;P4!2={B`D{?f5I0*8vKkr2mr^n=}F5qk3< zPv(ETNE3S{_R4Yb4ttmo>JQ|Irh3wd`jw>hrtWH zwP#0nDx8@zaBzHU^FYY?R6j@#JDOw$?~u7M*+|-R__rFpH-R&u@(6Vwfu*2LwzcPR z4;?2hI~5xjh@I3hFdY1p<{#;C)|Rf?^|~dbMSXy6UHI~Zm5n3H!*0FkG#` zTy$~`hen3+*eoQ)szun2LK1jlAPJSHT0(?c2oIRTr0i_^lDS)KQu@hjO_IXwf+zIf zGO*p1sMMK(7mf1BC~th}?_HOA+^J9hG=7-XfEkP@rpMYW3VeG;bNDq&n<#J@Z&{!5 zz|XNrOI(lQl)zI#C61l$H5RL2ohM6=ZxiD@={NO&tFbz$uQg%6B>ra#HGVzd+wCvX z!KBxMhr!P&ykYwUrL#QXlyV6VQjBcwR90Cu8$Q9!Q#O2kCD#9jB3eLvcq+TP*dPDvdHvLYta7$V6q^f_X51!?l6Ka+ z>$Vu?sQa2p5^VZ2oHK_Cq)tP6OC_O!$656mq;}vmnN=!TM55&lgVJj(^MX_6`3~$Q zm|1E_Z%wDOlnFO1pZCgK8y*HQC5}7?I@HoIe^K~w73j&$a9;Lo-aV44Xof0cD1i#( zrLA{A#n-CL>h%RjA;0S7$=bhn%SnfqWo;j$Jz);GLtI=Ss;WiZuJ#R|?!!x!e-5~K zYd?DGZByrf4(z%vGiOigkck2sZCF&iT%akPGrk)SAErdL*U_F31GK^pr5XodUu-4m zeSlN$+NVaMZ69GDit@sk9J*p(qDXd}=}YmVB77L>H)w@9_wOoLE|zTF%i)$aAC09&GKY7UMtWbfakJhYl@(K;^?dDp@mblY1S7-0 zI>y`S8aSnepFtyCP9bY`!qJ{YkI{tVvIJj~pBq;niG36GHOJ3e!!M9f>gw*DfbjeC z)SjxhF=YnnV6nQCN60ffkPYNO29M<`wZ$$?tHkH8$>y&e%$Sdt7~jj9%#=_ZmJL;8 z5R8}tLo=A}VX0xSB$$C2TyD~&f_Y4*Y0W!rZa7ue>DjE~EmRh;f0M1xW8tUP}>H^y=iD7I`uz7R4PJ z_0N$jE*ZGnQYs{b*G5u-Og`hGuXFAR^RM;jF--_Hq0cPgOqfSqR!AwTsz3E$lT4tE z&Ia4z@$2PJc<6baf>=7V&pjT-1PSl24Pk}nr_0Wo2<&`1o&)>#9WM!HTzJz+ zzBQiqGIj-K+>cWe(Ss}0O+6)B&ykwQLz$upoIr(wyElU2>0!9s7^;B}2$j_ucxHjmdPsBWl?5MDBt@SXNRc`o#+{}h)C}uoNH~&>HQyv~lOG;8A3zSagy2o_ z(z)QbiZMM0m%)dMs9RgX+JVl7frM8|_A`E>HCsD2qmaSOE2Zi|Khb8AS^QQWE|6g9 zF$mkPLltrVQ#gbo2~DYWKjO#fGVL#Ra9^;<_B^O8K~|8sm01wn8b2U+c-kye-!K0# zl1l5IzC3haDy=Q=8G&tbr-vaYzn&SbWTkz?T*`gqmCqH!#!XF_WbAB{8*$amS8kZG;u88Yt5{2Jm?ni^u>k#$?pw+u?jYgkF zHnl}SPYn3ayERwtO?B3#!f!RVEmT=45f{OSLI+!qgXQEp;wa(ZpJk%h6iPAp^py{8 zosK;e7wZ1A>OdS$8Bff-yn!oIe}=QEPN?uZzv$Gc#A@`H#Xn$BEn0@lsM z<=`uC*t3bV;w#$!mJUAZN7HEj{8Q8$1;TLbwhQ!oX9S8pYd82wsg#9kQ>Z0g*MF;* zz)vn$(gh0m3{rMo4Z<)1-ue31rP5Mc{a0hyJ=uuW2GB-i7PkX1^?6JjPoT-AOOI7% z`U**p2MDqwmF9O`vhxYBych3vfFWHmC+lks5c})E?4_R1WT&YaC(V;y*uIuWz-e%S z5p`MOS>_?sIN55g`Ua);MEQWWI`hL8g~L6S^REm`kbJu<*n6MqIZR~b@q4-j6Ha8{ zf7Bw+gP5?>q1e7KDwzUtc9-JK zzPCIQ9x4Cj8{b0;D|+gi<+kJ_2Qd$RRR9O>X%$(=f%a~Q-T)O{0u%Wmd9d7`QYxu5 zal`IS^9`02tNp_E!zhl%bX0J%e@984KF{lKiWSF15l=P2^%e!z`8oElx zEkDRnZ>!FSTCCT#VF{?}PaaZyhhupiW^?fVk9ort?fj*#^sZ_H>!v9|5q&UmkuQ@f zmD7|vspz$4zFklWs%y6%j$#-&QjUTRJ+E^qHpOp+`G4Nzurzm+m) z&SxBfSA>1+|8?O6x|9K}6l@>?&cO53<;dl9=SK_bx8gatKy^}!Qw`*7P>B7% zF4@Gq*NQF&ByVqV6dqvM*_#>Imj4i`5=i)A>CBJ18{8+xk2t@R3y`?mi+Gs_7+~FZ zW^e*wXLs4U8MC07ZzT->fL2zvD+tQ#va*Me!Mey4}a2v5J=)e^H~oxF$$crLE?t>{G|nW$T`3u38C$AD3xs1w+ z`2BdqJwZ;}YhP#A=WLz%g*pCfawj-=<|SRx^QbUAf<*B^BW||*h#FL zZVL)e?j|c`&V7Sd+?XXT3lo!)5c}Hb8gR00)13$@iasTvNq&B_{7w3<8lk3=xpR}U zUpGc^uISEK8pPU8{ghGAX2c!b@Xj4(s!e}<(r3;elb8LLEf9LRF7?v zJhW3RwE=mi;b?Pfk{!Bwc$hd`B7?In($$^yk50?X?bo^DaWC+3eR` zAc-hy;ffm11LD*O`P(Yi@#ohw>t<8}=MdJm6P_BmFtnIsf;G)qvXHEe2E9Z4F_RNZ32Ih}T~uZsKEsv2FF${!a+RuwJu z$@}08q#;I>b6?rhykLoGVgU-CBt}8X-QcD%s=$YEN@y!sew}%}2bi(Cp)p`@Z<0aE z^w8!E?@4}yz5O065?A6)_Iw4Is65G2FzEpaBxS zIGURg5pIPaKL1tW5);h6`MD_S{KalCp=(fFk4OFEqlDCsx`>~qSd%kht_(69tp$ODIX)LV|F&ZZ!oG3OV$!S5@A3KT`mfHU>ibmL@i+>47)rugrlY^F zY~E0e%N9piasGVGG^baLaM%rc_E)II@cWcbf(en@532BTG^0><>;_8sR4_Y;q1u-3 zfLgt4zZA)w9XPdmwTi{)zf=`FB@DEVN0I#3+T+&I^M1k&5@t_7(C4Sj{yLzrjl~^C zB#t5Sg$?*Aj0qBUW4$Q=z1@d-4K!c;W4Y}zxXhY(yH4kXTZq5+a`Nu+?wyKs@yN99 z_fNu9x8{^Pc#2Iz#0$5Sa@+3?{Fzi+s*?IgBsPYM`bQ!b7Y=g|>6{++(`cb+9v9(2 zTr6<)3V@+Xy?cHNgsLcD^|V|aL4Zp?el2q-mE=H`>6VLGhP!p^_)P)kZRQq5t;#m; z6-1b}PPx@xzdJJnwXt?G9nh6M!Es~eqo`*Hiu~#ag?9GoRup3Cldmi}T*C(;m zryF15#jl0cA#bw$2u6i39_3#X(_>N*Z&Zuu!1p48<7_UC>78`N86AbMSNI=I`a^&&8JnSzYMbBm0cUK!Lo6-b_kwVxSF} zWo*yO8h_=6_>rz?Lxtemv&-HiI<|IAe3CkYWg;wFJ)Ft`*hLQdS^hoA$AgwP%#^7? zgdc=`MpnJeoV#)C1m74?&?m}hGhyZ&17S>XGpXw5@{~@GCZe?DT~VyALDEmUVzfTb z`x1N{rV1y!GiehJ|3#61%SazoIXBkuAkcq?m-l#j-M()^$z8g%i>)1d>g+?tlx)h1 z+|`ag<6m15Ft^uJ)FYg-PWdeDS%+z7bw7Ke55u+N<=4;M9A7?+B#M4eJatbPNWW;f z`4uy$O|o)pvn0e*Go{&Q(Kl>?zZs0Du!J^*)Q-QrNtVU4ak@ED=bXSh(~>XkX6q>t zFZO7%{MWf~wPcRZS63N4H}^dehymkrLgY&krWsy5MUlVgUz)`uZYEFO%%hhkLkpn9 z^@fj#uvWN1?URQyOK+PoL?1gKZ>hn(!$-^mEdFbQR?)`*vYU3Bvhe-FdT}iTb&W{JP%t? zWFC9EvRhV+Qb~bPE#e&{$xV|lgyuEVsaIR$X;iqy76;CJ*ewrrKz8KuzVqlN@(+2m z*bu;^-rP}$>zNB${+1l|78&;aaZ!XVhWK%jHf!+3v zAz2;ZgypuK$Q(9WTM1S&V>&8WLXBtXeJo+d{G>CbdpeUKXywLOe@e*6(hM`(p zchcjB1AHtGgBh>7I-o6CRx79m9grgouL5TMU_^auhppw|X%=9d%^Rw+9ql z32R{4hM1Qykl88#>X0%?m_BD^&pMr&3>7=?CF`=ZQE9Bw<|$|~i6|u~cg=Z9;u;W6 z6p)osq47t>r+CB>G;{7~A4!#umX<`pp+}Ou_xW|W?!nT&s{}cMPzyC>!-in8$3@X4 zsLS4``%+&r&dw$S@&pOrKC?E_b^x;%f#+}Yg0%$0vMBrZU~TQCqSq(EOL(mpgN-+` zlQ*xs-~VBNjVzWe*8R~QCiQu6`F%?P%bz0p!O{)I@AJ4lqq-bzVCeiMd_jqf~j$j z2|B7u``|`Eq4Ze}@DN&Bo4&|Kw*aFu@gTHOysRDIp zk9Xh6x(22j+<%B?+}`LEjHZ6&iC&JB{B=1vx8xE>@be9O0dBl2ofv9CcY!Tw@I@D%&~{WT@93I2W1pk6~KnBL3h@%bNBO zw1R@T{lk?!tun=9QL_A%d*#~e=3Zc>yjdnirZ+KoJSf}>>5YqSv%;3fv>|EJa8<;K zDSnawyOz#K26q@u@q;CR>F2=HkV%Y-KYUHx8gb7~B_B!#s>a<6S^me zgN)|A!QKG)hx?fxP0o|ZhxB)p`Kaa#vUt6{zIl}TczZ$gt~{V`7W3fL=tqS-=KRd_FZltdVrL&v*mW~r{QZ;%KJM(XnJ7@` z7tKe1@w-bLM4QWF7eL}HFyrO-Dy4qD-$op;gDhE++pZe10C+&JC~+eRcbMT>`fAGk ze`Van&K2Xyaso}?Jo);}+Vf|4`1gUlyP=Zwk)3TiihJo85^0d9!2F zixN%R_1lAZ;a566x8tCNDi_sEM+)VY~GyKQtAu_-)_?P`Ht@ zUE7pwBTAxVhtx3V=sA7gP_oUn4Z?^u+z4hL-o*)uK>-NWlWbvckNt=AtBCr%j2)$& zmxjn97EkJ^c+t3J|M{B+04!R!Ul{_h)yYu$uw|5cwdApkdxOyv>ktP}t#HYJ*uZYl-^sK={qa?ORnw*&~Ge@4L)$mTHk>r9k>7p)T6)e^UFO1Ep2d* z-#0`peEU+>q#FNb)b;o%uu1AZK@HVvg}ZbZzATjQM*aw+D??PX)u%b@_#V z%Qzyv$Y0{($g$*zuK3OX@Ghm}GTlwP7_oqro5+WfC1SenR+2HkPA=FMQA8NsJ9-_&9Y4SmUv9`=9*+Ott5s zi;lnOMbVnmw091vdp(4`j;n58?7P%PflIExWqB`ATxqPqt*4L zNU5XdZY7-enCH(E{jFo?P%4~6h2%Ht(ifP!ahnp{!Q9XCQ=%tw6y%ZzR%^Rl zC(jJgmSaTuiR6`FjOtF3=tbDdCBiyt>#S2n znRe>zg>>gC2F^Uk>AA}&lp9bkoXD{_dqiA)p-DB&vO12JR&t8z|Y>Cf3H1% zKf&59xQK`a=ih&H0M9j(G~VJAf3LtKLi%Pz{#Z_HF1%Z2g7hz_o3pczI(3f+rC+=K zv26Fn`@xcYnd{Y(X&-LD1c84dnu?~snsRJP-qVro1Yn>=A>?=h*; z?i-N+)9o}3eP_r78yYqL*__5~vt{3NBfu07AZ|;piw#MKx$2Z!O7H0TI4;HSjGYLK zt)+z92OaeKw8b?qp7W7cY2)8zf3LD8`n6M=Zf=iL-Lmu!o2Rg=bufR&Y%5Q{9rbL* zUiL&!Hf29v^n8BQ0?(o$JfY%?86PRXFiMmrS;^f|6#kLRWisGM0~YK@7{0c+f+;VI z-Bf3HyF;`q9x?X$OuCC`N2=%j%L`guop=QGp&y{qPxOI^+I*L@+_n3mzq34CNM0Db z&i4OW0L#_YI}?|>gPq!@gf)kNrweYG!gk_IiNV#fw-+x>3QkR=1s)45OsML#%4dzw z+ir{K6hMp8iwSTtCyP8DQyY6EYleo(+}&i?d0(|$I?4mZb;=s=1kS@2qrI~fj}U@{@f!97kD1%K2w(;is)W2Wm($W6aj6-> zHy^0O7n`D7~$5hMM!mL1Zk3=6L zMf+Ynm00MuT_AZrZSiKIwYs2g<4eoGpcqA@pUvu8lkY&#Y}6Qo-zum;Vu7-20sYU) z`&0&qq{83U9IU@QJ&Rls@HJ;y5wk7NBEnto)94M{76Gj;l0Q=W2Ko@^8vfz+L``u| z!V!9q@3Tu38bEi>b$OVb4p&zd-)-1xW#!}>xBJqS8cOcs=!s_tUFb@ImAGr)8M{lj zuD#{nYa^f6dfnoG@!P$H3G8^7c$oX0`jTNP)Pk5L_0Ws)LK|fI?iTjcA)r*(p?UAq zBqn0Fp03P#aqe_D6r?xNKQkfJ$^0J3d;~r;{|T?>0R!p`Fuk#=R)XQf*d`V#rxU9y z{@TXM1uZnqc*E~g4b>ynSxnJU4GM-f4!f1$9`&mKH*}nYG}3aa`HWK z{w-p+{@Ihaqq=puAP_dd>d^;t$7S9PWQ>7Yk5@5`Z}et#3njO=k*%=GJSWlDCjj>N zlmyv+fgYLArAR0#Ciwn!ZruOPBtz&$594CJCzDA?sZ`0`tmh>{$3oX+@is$yU`SqZ zXy& zjxv7$hPWJgTvU1eu*Ui&cQDJzZ(V-$v(q)?Z+B8OJHK8*bgD;R$y(gBRdkNh&qJT0 z!^k9rVJ~qRb9t!yl9HLBoAkQ374(2a!R^j!l&=8lrltGyQt7S@N-B_0t!EhRb66vM zIbX&!t88b_r{uZsBYYv?8k{$a%hk-(;nCpKi8MT;h_Rl^jcN1LD}LaHZyrk6=Yl*8 zOP5a&zPn_V*Fk(O5M|S1i4+OL|GHM-GRDu25J4-|C^De%&Q}~zIBC%Dbw~zHEC({x z_OXCd-X-^iX2V7%&jl8a0USM|FD)CVEJ-DyBlO* zXW{x>|3%%(&KYL)@U`eRWQyMAJ9M1+R#p;CH`mDf#O$r?Zm>zKqZ3WCDRp^fTclKY znIovWt_LlD^LG;kV=O@eTli@gqE6MgZF7Vpj9?fIBfjfMRI@EWy9A;!&}sGbG~XTQ z^Q+M>-Il_nTgj>cJ;tUEBv$T();~Sm{q-hZyg&Dta7k~1(tWN?Tx-IReqD1toa)@nhzCs(QLIj3ygG#F96WoR|~A+rYC_&l^_ z7LG}*s6BpMji+$KpVsu<@ePIcvfk48*M6&^&K$b+U6#SlhR!6rccHXh?jLsFl(?0B zbVk?+2WV`@Gp#P72By|`q zh9jffO5M&vo8ML#WiAT;P{;M-w9GI+04|>vU5RvpsQNxH$b$Ctcs-!4<5>6!d#x&; z+Cfyl@!RO&s`cq#sod{v7IZ8Aefu<8s`KwzGc$L$TLQ5re+^@_751`8gLOy9jbmIN z8E_+2w$Im`!(eL52HdV@hdHqJ?ls9@=L&ZhlokSwb?IdylopU!nIaVr2;EE2H(E_A2lS|0G>{NA&{Qnr(ZeCoAN^*hS>e zKuCgeal3fA)tjb=;h8;m_?7vI^D zkl=@-yySybkiNgu^&FI`e#EYf%L|aDKmWW^_apD^|CsaFD%j6MHK5hsoo{Ii!EZOP z`m7l=l>Uf;e!0i$%jLQVa%V?u^vvx+)YM#bDNRg`WB#aaEE}=Kzjd7Uz9+F0U!>jT z`5c=zE!4?I>qOwI4seA_i_;iI!fHylfHR+zq~k2>XWwl-4-tQ86+WnK{jV63UgNCJ z%j0^NvJY+N(N{H<0fTr%JWrH}0hfKSB0mq&(7#*JD@fUAZLT-gtopb(6LvyS*JJp2 zs`OU{06eJ%M78AWbC)iD?KHHP?CKS2YExiaFCz>OaLSz2h;&+dP95VbQM%Q*@HAR4 zjC7EE`0t^D^1cuWGX9ME>c>|R%P#4zvsb^A=4NWk1a$~HCP@@VX+czrwkkeo;eKRhDRWJLk=16WXm1| zPS|%1B-)ir^vay3>8}Py!0k^07fdOAALk+rULeJKV=ic!JA?^4Jn{NGkQZUqmr7K) z@>WZDTaBQ`r&vnlrW;@5Ta)%X3eI$84#krW9MrbI0FzR=O${0`mmCbU!D<{T0oSpT zd_{nE0fhA#u%?`~^GpEzu>w?~habrYMncO z>w$8mkGMcKK%!uhsG}|p!R;I^MoEnzKkhV5QCW$^xy0cDatS>*1!XbNEU#%O-ufmx zhWPzt+bxL##R^l?j;hhUcT*z{wfu+rRmJ^@(f?S!tCuM&M0?_uT1yt=LtDbZtX*dU zoSl(Q^kF38-)6@$?I27RO!|JcZS7#JECF!-D-f+Tq$4A`#4Rx~a+E9ll;UIX=vbRQ z>b1pxD9MJPp{jR3@mqqPhNwdL;E6mSKg^HeC46!lB7M_>+y@HEZ7Kz0EK^xD;x?PncDz6B^N1^i57@J` zOg~o1q%vGTr}Gk#Eqv3&vA18peS~%#TOt(36!mU9g5sO;SltR5ztCpdytO)qXIyA{ zgrmv(f3(-GgLo&#&DH{In54LxKR2na2oRQcf2lD8fNMgKkTG7iJhpISUl#PU@W)0~ z=+Qr#zLR034uyKAtNg*ey!Eshl4myKxLKS!Wl2$hEI;kKdgc~OS@0J_c;oX?IxrU9 z$BQ#Z5T4M@b0>OvTuZrIMAtP}*2T~B{>!z}N)X+tU8^f^Jgyx|(Abi@k0Bu^ykQ8~e|_rnZ%K$!X+ zN2P|+`NsX-SVOz`Kez*kZxK9sP`x#Gss~#>$=Zu^V}bVEBRbEDAhS*(*k2aCxqea` z76;P&ahbf?Ql_RHhA2IGfCyFg4tVS(Z`+~8lcc{WYY&* z3;3F*v(#${W<({3d*6d z0=8$H_3E)~4SyE`62+dJ8E6)}NeO%l&`|gFT;O`U_Q6=QWeclKex4VBJh>fjfSe6> zh|aSxjwn8mA_6m>2cU{BLwkmcGbaX0Fs)EGvqF3n49}?y?VVa&i&OmIKY>X_Z8yfj zNO0k4c*pD+L&w3^Wa!Fmk<0Bf$y<4w^E}U6%{~Sxner~{(T3t)kavVNUSt}Ar*z}> zdAV5|vGvU({TH>1V%bem!nshL`bTG0Z`Vv`U$-Gu$11m8%%dj|lL?S$Aguni8rZ#Z zd*^t7@4vZbTG)L>D|r>(7M}6r>`eSj?~_-mg-&x(jf3bt>44IQA zhfkjipcs=OnVuK`@Vc`|Qt??{0!^SgzZ&DI96CDsXYc%e$^#5*xg3Z`6@AuT5Vbpr zM|H|z%~Do=O#5c|qu1cZ17#huc&sf?&W))SzlQHieNaWxv@etKADeyp{X*Jj{d^6p z|8|SIuca)*m)x#hv1^(^w#)@Pxu~k=QfuHk*?RLNaCSGE>;2f<7ZsSrP}O_!_hUIP zvAm^`SFNZnQ!iJ3*HqGnZxe6;B$EC;K%Pff4}_i!&;~UT+d_$1r^!)A?d+}kaFwM$ z1B($Vib!ovQ1zv;PQ=s`vpb=})>XXkTXTOaX-=N~?e+~w-O7W{t5$c$YRTon&%B$$p{KY&~RrCgfk zJ89ZB%A~)C54P+b{QeQsy>IXXAcv(KG)b&Q@H2F~^Ms0W@*Wa79)##LCEK{W=+n$Wi z4iceRV0ojvj!R>A#%m^V>)+`dkvu2+O$kzYE5bT;V(S`e2~6bJ%Zc<6I{5n4_&^J=rGqI zODpGhqSERz3|~0^9MDISVRic~``_K-V}u*QH-8;#_rso1%SZeu<3mDHuWZN!Q$;{%enlEK)3fK}f zj@(C9x_!TJ|Ec~Tx6*Vp7`rlgRrr{X{=8GB97a@QBt^_EPy99ccMpZ;H{WIJ0CTT@ z_O3Z^xCTy_YZZlU)j{)8o(^ZXn}EdPh9>_$|3O`Sr2|)^(cZKXdv+9Qe<&qKP@wV$2@*KFxvQOK92d;SZpkzWkD+Yf_n z^1ZC%_Dmal)Ye^^syfrhKJIWdlN*!eWX@6WvuL169=csSd#^?Js(-iLdi2gHZ0sK7 z`@og94;MnpxQc^fY2K8A)e*uivQjN-f2iaWJ6NCVYNoV@5-c+LpVs0-?3BJZf(D2_ zVn9h~LK-VircVN@D+F0|hIPL%>)dYdY-X|YnwPI>)f$@Nu%Z}2mT(`d60zc`TI5LH%={Hl z2XkME38rd-zOFSLhI+Yp@Q*Uym2i1@9mX)135Pc+N}?TwQ7yMzt+NjSVkeiaF0-he zEcVm#;oq`49j|F=w%OGV1gD~L>~t9Z4zo8?LanJaN(4Zz{8(MmJ8+797cXxSzTI}! zAOEYLH!u#P5*fOhe@&~z&T1RqJh)TERJ?@4FVeVRy2bD@jWTehH@EL3Pvbmq6E!}h^9h(SZd5s%t2PHYef#T*O)@HcZta$w3DDT(YPK*xTyl;~6YIB9QA z-ApN4KMw$n-4t?=+l4fWKM(I;g);LEe(IS!_wm*Qk&mNaNb&3k{8(8K0>f=^XBhq&DHId~7$4^=sn{(C48zO0Qezvr9 zkUqB?GORi&fCIRFvfv-^dBXg*Q$LTCb+6FW1uit&D#GYI9CT@{Yf_H?&AcvEt3H!; zXtzR!$As$rDIfy<80(Qpq5*|2U+_tD+lakpngr+&ySF{k)c3V+XNdP%Or_~KEp8?J z>Hd%W{F?pChf+xIw?!zlmY}1*u9y27dhYA0d`W)vy2QDNRVy0zeBUkea{A73`Fw`2 zBI9RFHE_G>eab{|p+{72QPZI1{bw#hOQdJEe)rhpz=tjyInE7S#EfpVZ0#bsf^TiU zk5@_FJan;OGI$mJv%>m78qoOFU{=Q&k;TP6j&S&+x6|Ej-D}S2DKB`7Y6`Y=pvg7q zml%uEJT)K*XEZ;{qlin_daMBU;i@&(&W$v=vlgiCde}Sd5G$-ma;>Sv* zY6IG6?GbKKV9VG6^VS9gBenb|8f5>?jyqrdOM1_R%LE^1;!Iy7D;4w_X=r*=E(KOS zj6LaJ6!nZIO&$0kCb)2&G&>P{{miU^jd~DDHqvZQC{FH?o#VCmp&Ki26v%S2jIY<$dpUH=nWj zgg$i06sN&3w2z2zVj0$TbT%da9`JGqmis7P>B_hN8cA10RFO^lBsAoRB=b!+66<|+ zg4M#0OhO52plUt;9Zo8`ev;oZ@>e@2!z)pCMD-YaSasyd9QRV?W4H`&T zJ4X$}dTy%IJ#Rf~kpXE-^%^dKT#`s3Jq5)1#>Zf1wlEQVr>?lozu($#LT8p?X{LHaN#CHT^Xw}lTLuLQ|;{vohocJw+q|foS1Q~ z>m1%@MUIW30|3K77t)zbW57S{leGp|rj>tAdBP9O@=Yy*Ksi^*59>!Sson$x(?)l; zRD34}edPIMBJMsz_?U&YCC85xJ?kZTNA9^Pf{>;)8OoT#>e1R9!GD9{H=H9hVfPcc z(aR2UcAMVs1m|rQ!3rkNN|2@<2W!SfF&6~b^k_UF!kYfo@XoN6uVyGpnSa%oG0~Z% zQ2Gu>Me?fHufeR&7vD7y@vQ)dcQ=sm;5utgJWw_OZL`ot%Z$-OeB(~jC-xKhRHF3L z7|XLG%(V33OU!c86N|)gM&Od4I5EHw?qV($Yx{yMUt-atRV6R7pg62)cIwaS#3>2G z89)g$M#ixsS9Ns}No#m{tKd$HMpSz-;-8<m$sR%^$QVKx0nVIi6vV*&t;J~$=J~LH$e08#-6s7v8lpm+3Df^yGF+&FQKy?Cr zyfz}(K0Ps*@M`HDj!l&pJoQ4|Z{F~glQ%d{40{smwNoB0g^89<>kFAr`(4j2YTK>~ z?$vDzt@ejUu@HL*)`X2M7rf$yo6cL;g|vU-H??&WaI-yuM;IS^lp(6fY#%a<$2&_R z1`}qh3%3uscONclsn|LN)tYaqz!2gae%2L)6qQp)3T4qps&K=UHLw$Kl@e=uqJLNF za8Z+cW606^ygO4z&AasdLECdvg$&9t&*V&ysp6sch`X)DPMf9+fdf!3Ro0fMzV)Nh zzAt-lACqxA{FwBwqC?aeNbQUrNiVXJ@Ye*6k#9lw!E zvnB$vD@T~aEZPQpi9plVzFlF>4OoPc8Gp>!V^B5tEoCS(6hr&yHd#jsDaDY`-H7Fg z=^rQB4SZq;^^^ni6htNrU-*3X-4g<|v6(n(E(A(=HsWA{XQlhcbAS9FxCRmfBCT>) zdwYkZ#XQl6EJ2p!77dn~mEBqdk2rKl2S?%5UE zu-%^k5-LE*_rMqS!%vuf^ZCxp#WqAY}9Hner3e{QWH#w%`^XExg;mt&K&sbD9O{V%fTx z##dpdWS;C)VSCJs_Yysf&3P889NM@(Az@Qz%yKj#K=ddi&#~OS!+i@|Wa#@Si#Pkk zg@A+o=Vlq(tojML3m{GHfP%K2 z4qyz*A^oBhT}e91wA&F`k-s1FA0pq=`K}yD@g!t;mf$G#fc^ps%O!Tv3zCm$kOP^S z)pZVCEop815WvXaUOV2FAiXu$0nzBNiqKQZyMA-5ls74T>cUjEmOm`jq}-!Vc|Io% z&H$HfoPH|U&p6=!8q^?C{*tytR%JQj-YkYXFa!X%8w;s%qfE+irz99l0|3|r)6DmnM=q5@`;ri2 zZtYilq$$55)-0Dg)A3$ub~Ix}d6>P$134f-M5(Hr30sax(tl)>gf(r2n+BRB1AO}2 zC4r9|3gdFNfGfKi!v|iJIq554q|sth{xaE8VV*Po>&xzcWjm|Nb3=KI_ZweuSfjaR zfGgIEfxPdryG6ixNx!YgWE*;pUHEOq^>k#2%0zTz@V0%#6Dep*Ok1y7T1XTLAFyh? z3FKW0INEVL)^3Z+YDsP}L+XFOw@*RVpgLb+cPm@3(kgWL;#pH9FL98nnZE8?T3xLF zc6{PY$)}Y0NME%$@Yg;G9|x4HNs4sVOOvE}n&P*D-@w?KqN!Om={?!|BYU^5)&DE$ zs^gmczW+12VU%=?Pzed8K?Y6%0YO5fK@g-tItC+ziAXmBBa{xMBuAr?A|d7YAR&Sv z?SQf0!}s@k?Vs&A=bn4db8eh-&v|cnzDKztah{8?K0i6_-TUeC<_oor-%Oo=yl!RPkoOXqResvG4iRd~~m5+eClR7?Zk^0+N zu=DHA`Zu)zg~FXCwc|}s?!N^2_E#qj@)P4*@5Pw;btNIsuA=(Q+h%_}UyveL88$<( z%BGf@*&jHg>Yp8f#;HptCL~|NlP+9IP7hxO#8`T}E;o}0=KYKt_ z{3v@mn7z;TK*NQqH;#>3ddp}q&Hoe-y$+u>@#&$u>Ol6~sz-8%R5U3Hr?fb&N z0J)8CB59w`Z_n~Syu#%2CIznoEU$0^6Au8F`vr`S@13$*2e3OUxiJG|Pp|RTjLOEy zM;qRjJHfv!979?uJ2fyg^!|qZ$+!}%`bOV`9h&K5Be048?vi@28}DYld85nt*vRVn z{^~ZMDn9M8VKl<<39Rd>oEemF`g)8Fb>Z&!Rq+V1L1Z5G4=`G#0-*jr?Vl&e*_e+Q zZPb_yy5sG;>Roku2Nr~)?|W1{3Hfh>hP3>R<@v!woj{FBXV31~`T5|wrmO;~hP_D! z|M0v&9%dpP+74D$02S@{WqaDBqdO=j=u5pImlWdLrb z1pJ!&dATO*$D(a2IOptR$Y*Fk3gO6(7ej~S3#Ku&CbaQjA>w|}tHmj)#k%`90T>LX zFNo4&4+(ouwhR}FhC-n!XcIFTQo}9wTOTGiF4<*nYyygIdqU#u*SVO$=lzcx-+6r{ z6QDDpx(0)#I@;I&OTAdR2?(Ajz&OALUXDZ#++uxNA3Mq^t<`+tIYwZc`@gGZ{)`hM_opZbg{{l$7!Et4kqe=IQDr zHC#-Tx|;$lx<;d`^_)t!s9ZBS`?BzKfb(?X!NHqj`Hn^sHd|;d%Oth@f5@{ z9RMY2_S=tGcoO&@B?J9M{BZYo#^9JTp|51z$Q@4hsp0d4R=`?{Qhh`AQsP=LpC5L{ zpH(_&YhNyGSQLm3JUEEz{k5Zk54UX?lxqVy zFT1g?TuZ6GD<3QUcy5vq&kSg`EIavIF3lI-8RLcj;t--&FxBfL}NG{YVjxe>fL%>jHfu+Fo znk)_2VO_k^ui%o`rZlxhY__vm)HTYP0LC zx!Z0*BH-Nj@51Gl3#<9!6<5RG*c7o5NCYl^H*eR8LCPgbtACTcUJjmU=Wa$m)&b20 zF+Qw`YsV1Hmabe(tIB?iyHkaaHJ$y|zC)uZKFyH#gMs@8Q(ib#OWFdK!J?qzgWj{VTRIh$Yf%+#w3e1RpwpZq*rth=l65nnK=9*u4n3| zAt$-!YzkQ23JY#t>+rbZ9<1(%rRYfC!m!uJZbm$IAdv?1&GNtlY0S3G@QFfvR%C6~ zT#-iK8CZn@7BW)3v(gfU!E{zOFa(QV!JX4NPfs1>*3@yi?}+v_H-Yc6sEr|UNOr~? zndJqiADi8w496VhO)Wu*)Xd1|2>;uziYIjI*+k1a z+2wgjL48ChsKdEt912Dvc@;Fz=;cYl4Q!7pfdDuq-odk)3}XB)VLqOLs!i#ja|Gd1 zW*IVvJ)0hcdzgK1#AdxZ;U$LgEuQ@Y3jrrvj={-9hflw9KxUV@5uHV;?nT_=m1;e7 z1M}M}81M1t30ppn{mp6;YrirCMqyc#ETOJ@*;~I-C9$+d`Nx_|K0>fp;nT4Vb2AcviQ+tR!*@2MP)qosW;O_&5(>mJ!ZDHR z%o<-WmdXm^DmE}+7WKiqRlT|RsaIEOv4Xf$OU}}tKAIS9lU}g|B2^-hobJ!`@~-CN zn6F;FdqjE%+&2b(7q!UotFvc3TMqz=6KRgJnQj<8+q`EgOJVG1{wnXOxAjkuw?Rx5 zha?S-kBQpCvTi@l)NQSEIR`7{>a|Jr33Q3)MIbUow~rK^1hwKZs2YRX66njpkmHMS zvqI0o0L|sx78qJsLz>Sm; zT%pPnT*+#93}rC4s=lCWh`JqYN#cq&s(U#Y?bJ>`{T(^h)i(RfyWY^$tC*{A8T`#QXoI7^db)SU{iCFSYoRasLES<7u*e-{}b(Njb6 zs7*4D30fmjc$&!vy$TPS63J43k}|m`Lfn>_raGBfvUm4BguY{JsG3N)_9I|?MCt4d zh=QmGT_ih>5zjZ&iF+bg=tT6*o|{T1VfEUX{nP6_H3}k-i46GX+}coq*&P)c^Z3tw zZGrz1HA{=e*clDo2O~aSrv^|p@)sSN{aHIFk>(p9(S6VSP`<~);#|lhuda6@K$94} z!kmaq5%zbFs|`hJ3F>Zsr_U#Jl`y#^i&_!#>RiA!JSJOTXs^J&pHl}8O8htP2NW~l zz;_heG+I-tAP1Qck4zQW;z!Z*AM?JDc<0Q282%}c6-Ga~S{L!`ISHl*o+^Up`yR~E zwsXgfEucvHJn2ExVsh??SG%7*A8=VfgjBcJ{+_uvAJfaDq@`f&TgEwrf4dg4w68+n)bM~dD7=e7ulgm^SUbs zbMWE7{JgSqgI?XIB^BJUTm8{D?}H)fJsv&KkCHlNxM4XDCi{h2S76Wb#ZGkZao&Hg zv%ba8tOvwLr_+`x+QSO;Tu0f4HEO{+5`?%Ra=7N|rt`f0lFE`4)coCPTr#k;MLZY! zOh2L9{Nnmw8^A%pRoAH|h+WJ}q#+ZnjTTF@6Q`DBhXxGD^)wLM5G<(WP>A01QA7ZH zW!mRz5g2oE5c9T`tlQcQiyuky>Rg2Nepa?-EeVI&7yYRG=r4KyPxK|GDppkR3#IDS z-o9D&AZ-97$)pbB+)Q z%_mjTN5$>*88OZI_Fd~a{g)i#Xx2E60mH+li$B>N?X&q*wBOVtb7-k+uELm;=X9lw z@9(g~hZs(7-oD0%z36cu0qm;mO(A+WddPt6c9NS}sg?!^VOHNP`_rS|T&y)qvt-16f!(dXdj&z#j6R_LBcfxr5RXGij4?w^Ie5ShvD z@+7wi+F%0!Sm6;OdoC$GOP}Aaqpraj_NrqAdj#1id5@C6d1~`++hV z!T>NpNU-burw>kbdMD^$nGpSkwJ_m9$HOryth(gLMAjHhA;zycuTy-iNJtw6I`7)a(V97&ZTK^Db&k?Q?A_2X6L) zokk2owPs-#PV0xIEv|K(?c76tRHSL(f=a+Rjjs2-#lCnMp&PJN&Z~U3#0JOFC7gC0 zw-_3NqU7j)whB%lCX7+dF@q$t0}ax9YJvA2<=+qRfTlR1o&Ov4`55p;?INvo@!qds zpctS4UQGT|u=NJDo@_)#A8CEkT7oJae=Wx1{l|8>=3pllh1Ry1`)(><7e>2YE86if zGSOoK8PU7-<2I{Q9YIp$BN@>9j4GiGvq8#KV-WslPW8$?gemsA@T7d7&w~}(lH)4+>F`^feq8lnGmDa;s-&FX1 z-gWpVX)A-^HEb=|Ui@A7(BI1$cMjF-+!kX2?|Qdhz+g55(s=5Yo8(gxy z8VPsY;<%Ts1drtH6{5vievCA?i%w|aQ=VZ|Qj-UrF_E_J{Dn%^$tYsN=Sp>`l>1pi z`%kWU?patWvibL5wk>b;)`s1&oVqiCcI|Yz;3{S#`r?VSbcpAt2>u15-Vokk=!~?x z#71Pl<-Q)7^+|7Roc;P%_^`$D1!Z11xs%O{t?^c~+L zBX>HJMRkv9UY)TH3a|X=&%1pi(J$i}vbAoz*McuA+KMPL5dj7??$4YK*D5!+ zR*5L__eCNQtIfp^zVG`4o^QTtvQIqgOarNa0WHp(((6z6sN_{wMakmP+8n31X^@Pw zxrJ&}dvCF8+ScGHRg3N{M7(>|es-hiw+<4cC`Iy7rz8S_Swh9+JY#aAGJqdJNEexjCxIVNH8CKO)=NM2$ zeiu+xb%jRxiW(3&t4~nXntsF!Ra59AbX8x>Nh}^+n)g`)C)In5^ClfXC)1eYqEM^( zAzfi`xs6B^a7ibe(FUCqYT|}&1(+d9E9efxr~)Fs>MI|~r45w+{et`B_++^4(6nIT zh=W^3b=3ix7Izf7R6dgP3O=pH3WITGM*pC+ABR3$_$8Gv--x|>es@B#q7IlEP`Vdp zO;7geqcXuKO$3u-=lHPJlaEReo}F5we;Rz9Tw88hQ3!}W*T(373O z2S@IHJU=nyGjqV8KUw4i{6bO%gtIH}9w}^>1?*rIXx|ds^mrgs)*-q3i9lCHfZnos#|%(m_`Bg# z5VbP_EV*X~W)}2KABoM9E`(2a?qu2SoXF$SuBIs7+dm%% z@;C0r%*__bLdZ^Io6*|Ru#@uf#PObETgK)1rXs&^v_VK>@paj0Qt86oaFjB4-$<1= zp5J~2SM+?z8FZEZi=WZhmFhmm#ncv_SngAH8-9rGk;p$A&zd6xXHYzZMP^5Z0W~*l zc)@2y5FN1ss&~-{1c^Py;fnhrBR6G{Lkli7BL6j~-a$F;ts{6+-^xW0}8&B1BDs0s%ji3#Zo|DsbPwZb#2M3{kcIr27P z3@%WDcGN0HVZ6H^+j~fk_Bu_}MwGty^f+g18wzXNIpF>3;n=b1Rg|d%05n&xXY>3F z>f)@=&Y_jYBeTQ!YKeh0FwAWTR7ac?Z}XT4R7=56+QH);lClX+_u$m>zAiYCUwq?{ z|C_$6$j&mZdDN!Dmo3rT@9X`Ova5s{YMzs*R=;Q8vKP1=(>w}U+{BW)DVc<&%iw&3 zE7q6+6tax-{om4E#Y|>{_MfPVtp83U+P-ujCM{*#LsOEox z#Zlxd8E=VKX&0Hy|M+zewnJlo&ioa@`BYC?alW%bRq*$WW)&I5{?@PmwzF6CktBe^ zeIT$DmdYkt>9MLb+gZ33Th6l9iDyOI4MZs zr(1<`JhCx?YThFAr;Bx$J_$GjVX;Q;9LKz|23=PrLrr-~-Ra|`YrY*_hfVH>hb+}? ztFRVYoKj(Kta3uYzz$q8V3zp6qK(ARjHlF5oF{5#jN&drc68}Ty>t}!kld~y*@h8Z zn+HEYLtjO+B8Q+froj63osERIO?jFK#D`Da_433P5a|x?gMLV>g&Y!u!Cu=h|7tCA zSO3!vq78bMDE9l14uxGla5K)^4_pl75&VK@5HP8W$hg_gHw15^B!7u+tbD|~*KTzm z*nxvlENx|%1KV6?l*lz|CaBI8kBi|FGCR(6GBmn0TAsKDiqpGKfDq3G36n zQB>%M;(Q!)!~p$(orj4Wit8#2(3Hk<`hQ>7agLRMaOqz<%Gdv0_tQ5-tRB-nbx^8Q zx%g}d0)8$rF+t5^whq-zcuIe%q(3Sm6R^Kj2D^9uMcmYOmV^jUP_AT%Ad^=0pw|L7 z4rJV8z2Fek2AVNsVn_-kV|yTD_gwX@5CrPNnY+nPCIUbVZBgh(y8IJL za2)WdD*`Zcr)30>O!2{m^fd^T-ha2W61He3IsoWria;zed+e+ayfA_*Gc%=(Oz4L9 zOkP_CrukWV_Zu(u^k}%7+U7MWKbq44Y;8z$3u{Z+vwk*oJt*H?PVByP(BD3D~6U*gU$=^-xzq1mG+J zsc+@io;;0bM$tW#gClaaZ3&zpl4rCDJyS~TSMvy`O?Eg1TO7xpSPC{Ek+*Zy0_sXq)0ph8qfYJT-Tqd=dtq^~QP8|zlCXpOrkrc_|)35E5{9*TTKfee- z0)k0rKU}uQy+><*d($K%Bz8gz;$xFf@e8DC#1_{)H{r&Pl##(bbzh>iDLB5&Ja1I& zFW)s3R=p3bCZCwUPPSmflO zR27B{{zwmOMxb$Tm6TpLc3%TuLuB8x513CD&z=|Fdd&>DRQBr7h_0Z2a50%fh81eoK7uWZ zf_U6$%Or-os?|RsDGL+$E@3@tl<jpV=74|NyaQVj1{mkAdoBB-A6>V z2-HoKX;5r51;cNO$kN0jy%BT&ecewWa`#_9guwM;W^8FJhyk8q=@6Ger>)qysVfE| zPfr=i3h=pn%bEfK%5%KMIqP|<<(Ph36x~WJN>~eCn$3~`dyr$IIDnGjneiYok1pgG ze(cUEWbiPr%Ml#(=MHets~pnaOuTHLo`j!fs1Hgw3>X;g^QLOw1l!LvRvdskDn6qp z?LI>e3E8N5NjM*7NY!XlqZ%7~6_F;KXgfHyhORgF?Kgr$oF4xszknAuBgPzMNi^hk z-3U6nAS@S+apj{)h0NlvzjwnyRO%FwsSqlfL0ME0s*v`aGBWyGPwb&f37!xGn?-;#^J zBt_P*RjSyQ%7DUeng1tDPKRs}qnJo4;_q9Mw3YMDJ15I5jx=(==2CJ+2UH_8$y1J( z>s0!X<(pX*-ysB9@qqbvo{Fcjf?-!v&rrHa^OZeaYLqq&Yu6ohrBm0JQDU-$$XLT_{yxA$ TtQq`M06^#N14ON+UDW>p{2tJk diff --git a/apps/frontend/public/robots.txt b/apps/frontend/public/robots.txt deleted file mode 100644 index 1f53798b..00000000 --- a/apps/frontend/public/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: / diff --git a/apps/frontend/src/app/api/trpc/[trpc]/route.ts b/apps/frontend/src/app/api/trpc/[trpc]/route.ts deleted file mode 100644 index 76e6033c..00000000 --- a/apps/frontend/src/app/api/trpc/[trpc]/route.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { appRouter } from "@opentrader/trpc"; -import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; -import { cache } from "@opentrader/exchanges"; -import { PrismaCacheProvider } from "@opentrader/exchanges/server"; -import { headers } from "next/headers"; - -cache.setCacheProvider(new PrismaCacheProvider()); - -const FRONTEND_ENABLE_TRPC = !process.env.NEXT_PUBLIC_PROCESSOR_ENABLE_TRPC; - -const handler = (req: Request) => - fetchRequestHandler({ - endpoint: "/api/trpc", - req, - router: appRouter, - createContext: () => { - const password = headers().get("Authorization"); - - if (password === process.env.ADMIN_PASSWORD) { - return { - user: { - id: 1, - password: "huitebe", - email: "nu@nahui", - displayName: "Hui tebe", - role: "Admin" as const, - }, - }; - } - - return { - user: null, - }; - }, - }); - -export const GET = FRONTEND_ENABLE_TRPC ? handler : undefined; -export const POST = FRONTEND_ENABLE_TRPC ? handler : undefined; - -export const generateStaticParams = - process.env.NEXT_PUBLIC_STATIC === "true" - ? () => { - // Workaround: - // Next.js throws an error when building a static app and empty array is returned. - // Error: Page "/api/trpc/[trpc]" is missing "generateStaticParams()". - return [ - { - trpc: "_", - }, - ]; - } - : undefined; - -// export { handler as GET, handler as POST }; diff --git a/apps/frontend/src/app/dashboard/accounts/page.tsx b/apps/frontend/src/app/dashboard/accounts/page.tsx deleted file mode 100644 index 19793e56..00000000 --- a/apps/frontend/src/app/dashboard/accounts/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import dynamic from "next/dynamic"; -import React from "react"; -import Loading from "src/components/accounts/loading"; - -const AccountsPage = dynamic(() => import("src/components/accounts/page"), { - loading: Loading, - ssr: false, -}); - -export default function Page() { - return ; -} diff --git a/apps/frontend/src/app/dashboard/bot/[id]/page.tsx b/apps/frontend/src/app/dashboard/bot/[id]/page.tsx deleted file mode 100644 index 57c6675a..00000000 --- a/apps/frontend/src/app/dashboard/bot/[id]/page.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import dynamic from "next/dynamic"; -import React from "react"; -import BotDetailsLoading from "src/components/bot/bot-details/loading"; -import { toPage } from "src/utils/next/toPage"; - -const BotDetailsPage = dynamic( - () => import("src/components/bot/bot-details/page"), - { - loading: BotDetailsLoading, - ssr: false, - }, -); - -type Props = { - params: { - id: string; - }; -}; - -export default function Page({ params }: Props) { - const botId = Number(params.id); - - if (process.env.NEXT_PUBLIC_STATIC === "true") { - return ( -
- Page is disabled due to the static export. Go to{" "} - {toPage("bot/:id", botId)} instead -
- ); - } - - return ; -} - -// Workaround: -// Next.js throws an error when building a static app and empty array is returned. -// Error: Page "/api/trpc/[trpc]" is missing "generateStaticParams()" -export const generateStaticParams = () => [{ id: "_" }]; diff --git a/apps/frontend/src/app/dashboard/bot/info/page.tsx b/apps/frontend/src/app/dashboard/bot/info/page.tsx deleted file mode 100644 index 0102f015..00000000 --- a/apps/frontend/src/app/dashboard/bot/info/page.tsx +++ /dev/null @@ -1,23 +0,0 @@ -"use client"; - -import lazy from "next/dynamic"; -import { useSearchParams } from "next/navigation"; -import React from "react"; -import BotDetailsLoading from "src/components/bot/bot-details/loading"; - -const BotDetailsPage = lazy( - () => import("src/components/bot/bot-details/page"), - { - loading: BotDetailsLoading, - ssr: false, - }, -); - -// This page is used only when building a static app (`export`) -// It is a replacement of dynamic path `/bot/[id]/page.tsx` -export default function Page() { - const params = useSearchParams(); - const botId = Number(params.get("id")); - - return ; -} diff --git a/apps/frontend/src/app/dashboard/grid-bot/[id]/page.tsx b/apps/frontend/src/app/dashboard/grid-bot/[id]/page.tsx deleted file mode 100644 index 508c93ab..00000000 --- a/apps/frontend/src/app/dashboard/grid-bot/[id]/page.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import dynamic from "next/dynamic"; -import React from "react"; -import BotDetailsLoading from "src/components/grid-bot/bot-details/loading"; -import { toPage } from "src/utils/next/toPage"; - -const BotDetailsPage = dynamic( - () => import("src/components/grid-bot/bot-details/page"), - { - loading: BotDetailsLoading, - ssr: false, - }, -); - -type Props = { - params: { - id: string; - }; -}; - -export default function Page({ params }: Props) { - const botId = Number(params.id); - - if (process.env.NEXT_PUBLIC_STATIC === "true") { - return ( -
- Page is disabled due to the static export. Go to{" "} - {toPage("grid-bot/:id", botId)} instead -
- ); - } - - return ; -} - -// Workaround: -// Next.js throws an error when building a static app and empty array is returned. -// Error: Page "/api/trpc/[trpc]" is missing "generateStaticParams()" -export const generateStaticParams = () => [{ id: "_" }]; diff --git a/apps/frontend/src/app/dashboard/grid-bot/create/page.tsx b/apps/frontend/src/app/dashboard/grid-bot/create/page.tsx deleted file mode 100644 index 00ef11e5..00000000 --- a/apps/frontend/src/app/dashboard/grid-bot/create/page.tsx +++ /dev/null @@ -1,16 +0,0 @@ -"use client"; - -import dynamic from "next/dynamic"; -import CreatBotLoading from "src/components/grid-bot/create-bot/loading"; - -const CreateBotPage = dynamic( - () => import("src/components/grid-bot/create-bot/page"), - { - loading: CreatBotLoading, - ssr: false, - }, -); - -export default function Page() { - return ; -} diff --git a/apps/frontend/src/app/dashboard/grid-bot/info/page.tsx b/apps/frontend/src/app/dashboard/grid-bot/info/page.tsx deleted file mode 100644 index 27948432..00000000 --- a/apps/frontend/src/app/dashboard/grid-bot/info/page.tsx +++ /dev/null @@ -1,23 +0,0 @@ -"use client"; - -import lazy from "next/dynamic"; -import { useSearchParams } from "next/navigation"; -import React from "react"; -import BotDetailsLoading from "src/components/grid-bot/bot-details/loading"; - -const BotDetailsPage = lazy( - () => import("src/components/grid-bot/bot-details/page"), - { - loading: BotDetailsLoading, - ssr: false, - }, -); - -// This page is used only when building a static app (`export`) -// It is a replacement of dynamic path `/grid-bot/[id]/page.tsx` -export default function Page() { - const params = useSearchParams(); - const botId = Number(params.get("id")); - - return ; -} diff --git a/apps/frontend/src/app/dashboard/grid-bot/page.tsx b/apps/frontend/src/app/dashboard/grid-bot/page.tsx deleted file mode 100644 index f465f4d1..00000000 --- a/apps/frontend/src/app/dashboard/grid-bot/page.tsx +++ /dev/null @@ -1,17 +0,0 @@ -"use client"; - -import dynamic from "next/dynamic"; -import React from "react"; -import BotListLoading from "src/components/grid-bot/bots-list/loading"; - -const BotListPage = dynamic( - () => import("src/components/grid-bot/bots-list/page"), - { - loading: BotListLoading, - ssr: false, - }, -); - -export default function Page() { - return ; -} diff --git a/apps/frontend/src/app/dashboard/layout.tsx b/apps/frontend/src/app/dashboard/layout.tsx deleted file mode 100644 index a514e1f3..00000000 --- a/apps/frontend/src/app/dashboard/layout.tsx +++ /dev/null @@ -1,65 +0,0 @@ -"use client"; - -import type { ReactNode } from "react"; -import { useState } from "react"; -import { ThemeSwitcher } from "src/ui/navigation/ThemeSwitcher"; -import { AppBar } from "src/ui/navigation/AppBar"; -import { AppVersionInfo } from "src/ui/navigation/AppVersionInfo"; -import { FlexSpacer } from "src/ui/FlexSpacer"; -import { LeftNavigation } from "src/ui/navigation/LeftNavigation"; -import { Logo } from "src/ui/Logo"; -import { Main } from "src/ui/Main"; -import { TopNavigation } from "src/ui/navigation/TopNavigation"; -import { AppDrawer } from "src/ui/navigation/AppDrawer"; -import { MobileDrawer } from "src/ui/navigation/MobileDrawer"; -import { DrawerToggler } from "src/ui/navigation/DrawerToggler"; - -type Props = { - children: ReactNode; -}; - -export default function DashboardLayout({ children }: Props) { - const [drawerOpen, setDrawerOpen] = useState(false); - - const size = drawerOpen ? "md" : "sm"; - - return ( -
- - { - setDrawerOpen(!drawerOpen); - }} - open={drawerOpen} - /> - - - - - - - - - - - - - - - { - setDrawerOpen(false); - }} - open={drawerOpen} - > - - - - - - - -
{children}
-
- ); -} diff --git a/apps/frontend/src/app/dashboard/login/page.tsx b/apps/frontend/src/app/dashboard/login/page.tsx deleted file mode 100644 index 1d2fd80f..00000000 --- a/apps/frontend/src/app/dashboard/login/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { LoginForm } from "src/components/login/LoginForm"; - -export default async function Page() { - return ; -} diff --git a/apps/frontend/src/app/dashboard/page.tsx b/apps/frontend/src/app/dashboard/page.tsx deleted file mode 100644 index ee2ed23b..00000000 --- a/apps/frontend/src/app/dashboard/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { LoginForm } from "src/components/login/LoginForm"; - -export default async function Page() { - return ( -
- -
- ); -} diff --git a/apps/frontend/src/app/layout.tsx b/apps/frontend/src/app/layout.tsx deleted file mode 100644 index a0100fbf..00000000 --- a/apps/frontend/src/app/layout.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { cache } from "@opentrader/exchanges"; -import { PrismaCacheProvider } from "@opentrader/exchanges/server"; -import { ThemeProvider } from "src/providers/ThemeProvider"; -import { StoreProvider } from "src/providers/StoreProvider"; -import { TrpcProvider } from "src/providers/TrpcProvider"; -import { TRPCApiErrorProvider } from "src/ui/errors/api"; -import { SnackbarProvider } from "src/ui/snackbar"; -import { ConfirmationDialogProvider } from "src/ui/confirmation-dialog"; - -cache.setCacheProvider(new PrismaCacheProvider()); - -export const metadata = { - title: "Opentrader", - description: "Opensource Trading Bots", -}; - -export default function RootLayout({ - children, -}: { - children: React.ReactNode; -}) { - return ( - - - - - - - - {children} - - - - - - - - ); -} diff --git a/apps/frontend/src/app/page.tsx b/apps/frontend/src/app/page.tsx deleted file mode 100644 index aa2ab86f..00000000 --- a/apps/frontend/src/app/page.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import { redirect } from "next/navigation"; -import { toPage } from "src/utils/next/toPage"; - -export default async function Page() { - redirect(toPage("accounts")); -} diff --git a/apps/frontend/src/components/accounts/AccountsListTable/AccountsListTable.tsx b/apps/frontend/src/components/accounts/AccountsListTable/AccountsListTable.tsx deleted file mode 100644 index fecc66de..00000000 --- a/apps/frontend/src/components/accounts/AccountsListTable/AccountsListTable.tsx +++ /dev/null @@ -1,121 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React, { useState } from "react"; -import Table from "@mui/joy/Table"; -import Sheet from "@mui/joy/Sheet"; -import type { TExchangeAccount } from "src/types/trpc"; -import { AccountsListTableRow } from "./AccountsListTableRow"; -import { AccountsListTableToolbar } from "./AccountsListTableToolbar"; -import { AccountsListTableHead } from "./AccountsListTableHead"; - -type AccountsListTableProps = { - accounts: TExchangeAccount[]; - onCreateAccountClick: () => void; - onEditAccountClick: (account: TExchangeAccount) => void; -}; - -export const AccountsListTable: FC = (props) => { - const { accounts, onCreateAccountClick, onEditAccountClick } = props; - - const [selected, setSelected] = useState([]); - - const isSelected = (accountId: number) => selected.includes(accountId); - - const handleClick = (event: React.MouseEvent, accountId: number) => { - const selectedIndex = selected.indexOf(accountId); - let newSelected: readonly number[] = []; - - if (selectedIndex === -1) { - newSelected = newSelected.concat(selected, accountId); - } else if (selectedIndex === 0) { - newSelected = newSelected.concat(selected.slice(1)); - } else if (selectedIndex === selected.length - 1) { - newSelected = newSelected.concat(selected.slice(0, -1)); - } else if (selectedIndex > 0) { - newSelected = newSelected.concat( - selected.slice(0, selectedIndex), - selected.slice(selectedIndex + 1), - ); - } - - setSelected(newSelected); - }; - - const handleSelectAllClick = (event: React.ChangeEvent) => { - if (event.target.checked) { - const newSelected = accounts.map((account) => account.id); - setSelected(newSelected); - return; - } - setSelected([]); - }; - - return ( - - { - const account = accounts.find( - (account) => account.id === selected[0], - ); - - if (account) { - onEditAccountClick(account); - } else { - console.log(`AccountsListTable: Account ${selected[0]} not found`); - } - }} - title="Exchange Accounts" - /> - - - theme.vars.palette.success.softBg, - "& thead th:nth-child(1)": { - width: "40px", - }, - "& thead th:nth-child(2)": { - width: "40px", - }, - "& thead th:nth-child(3)": { - width: "360px", - }, - "& thead th:nth-child(4)": { - // width: "100%", - }, - "& tr > *:nth-child(n+5)": { textAlign: "right" }, - }} - > - - - - {accounts.map((account) => { - const isItemSelected = isSelected(account.id); - - return ( - { - handleClick(e, accountId); - }} - selected={isItemSelected} - /> - ); - })} - -
-
- ); -}; diff --git a/apps/frontend/src/components/accounts/AccountsListTable/AccountsListTableHead.tsx b/apps/frontend/src/components/accounts/AccountsListTable/AccountsListTableHead.tsx deleted file mode 100644 index 92b92f7e..00000000 --- a/apps/frontend/src/components/accounts/AccountsListTable/AccountsListTableHead.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { FC } from "react"; -import React from "react"; -import Checkbox from "@mui/joy/Checkbox"; - -type AccountsListTableHeadProps = { - numSelected: number; - rowCount: number; - onSelectAllClick: (e: React.ChangeEvent) => void; -}; - -export const AccountsListTableHead: FC = ( - props, -) => { - const { onSelectAllClick, numSelected, rowCount } = props; - - return ( - - - - 0 && numSelected === rowCount} - color="primary" - indeterminate={numSelected > 0 && numSelected < rowCount} - onChange={onSelectAllClick} - slotProps={{ - input: { - "aria-label": "select all accounts", - }, - }} - sx={{ verticalAlign: "sub" }} - /> - - - ID - - Exchange - - Credentials - - Created - - - ); -}; diff --git a/apps/frontend/src/components/accounts/AccountsListTable/AccountsListTableRow.tsx b/apps/frontend/src/components/accounts/AccountsListTable/AccountsListTableRow.tsx deleted file mode 100644 index a0a02b7e..00000000 --- a/apps/frontend/src/components/accounts/AccountsListTable/AccountsListTableRow.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import Typography from "@mui/joy/Typography"; -import type { FC } from "react"; -import React from "react"; -import Checkbox from "@mui/joy/Checkbox"; -import Chip from "@mui/joy/Chip"; -import Box from "@mui/joy/Box"; -import Tooltip from "@mui/joy/Tooltip"; -import type { TExchangeAccount } from "src/types/trpc"; -import { ExchangeIcon } from "src/ui/icons/ExchangeIcon"; -import { formatDateTime } from "src/utils/date/formatDateTime"; - -type AccountsListTableRowProps = { - account: TExchangeAccount; - selected: boolean; - onClick: ( - e: React.MouseEvent, - accountId: number, - ) => void; -}; - -export const AccountsListTableRow: FC = (props) => { - const { account, selected, onClick } = props; - - return ( - - { - onClick(e, account.id); - }} - > - - - - {account.id} - - - - - - - {account.name} - - - - - {account.credentials.isDemoAccount ? "Demo" : "Real"} - - - - - - -
{JSON.stringify(account.credentials, null, 2)}
- - - {formatDateTime(account.createdAt.getTime())} - - ); -}; diff --git a/apps/frontend/src/components/accounts/AccountsListTable/AccountsListTableToolbar.tsx b/apps/frontend/src/components/accounts/AccountsListTable/AccountsListTableToolbar.tsx deleted file mode 100644 index 897d3d97..00000000 --- a/apps/frontend/src/components/accounts/AccountsListTable/AccountsListTableToolbar.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import type { FC } from "react"; -import React from "react"; -import Typography from "@mui/joy/Typography"; -import AddOutlinedIcon from "@mui/icons-material/AddOutlined"; -import EditOutlinedIcon from "@mui/icons-material/EditOutlined"; -import Box from "@mui/joy/Box"; -import Tooltip from "@mui/joy/Tooltip"; -import IconButton from "@mui/joy/IconButton"; - -type AccountsListTableToolbarProps = { - title: string; - numSelected: number; - onCreateAccountClick: () => void; - onEditAccountClick: () => void; -}; - -export const AccountsListTableToolbar: FC = ( - props, -) => { - const { numSelected, title, onCreateAccountClick, onEditAccountClick } = - props; - - return ( - 0 && { - bgcolor: "background.level1", - }), - borderTopLeftRadius: "var(--unstable_actionRadius)", - borderTopRightRadius: "var(--unstable_actionRadius)", - }} - > - {numSelected > 0 ? ( - - {numSelected} selected - - ) : ( - - {title} - - )} - -
- {numSelected > 0 ? ( - - - - - - ) : ( - - { - onCreateAccountClick(); - }} - size="md" - variant="outlined" - > - - - - )} -
-
- ); -}; diff --git a/apps/frontend/src/components/accounts/AccountsListTable/index.ts b/apps/frontend/src/components/accounts/AccountsListTable/index.ts deleted file mode 100644 index 28c08a13..00000000 --- a/apps/frontend/src/components/accounts/AccountsListTable/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./AccountsListTable"; diff --git a/apps/frontend/src/components/accounts/CreateAccountDialog/CreateAccountDialog.tsx b/apps/frontend/src/components/accounts/CreateAccountDialog/CreateAccountDialog.tsx deleted file mode 100644 index d5ead222..00000000 --- a/apps/frontend/src/components/accounts/CreateAccountDialog/CreateAccountDialog.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import type { FC } from "react"; -import React from "react"; -import Modal from "@mui/joy/Modal"; -import ModalDialog from "@mui/joy/ModalDialog"; -import DialogTitle from "@mui/joy/DialogTitle"; -import { useSnackbar } from "src/ui/snackbar"; -import { CreateAccountForm } from "../CreateAccountForm/CreateAccountForm"; - -type NewAccountDialogProps = { - open: boolean; - onClose: () => void; - onCreated: () => void; -}; - -export const CreateAccountDialog: FC = (props) => { - const { open, onClose, onCreated } = props; - const { showSnackbar } = useSnackbar(); - - return ( - - - New exchange account - - { - onCreated(); - onClose(); - - showSnackbar("Account created"); - }} - onError={(error) => { - showSnackbar(JSON.stringify(error), { - color: "danger", - autoHideDuration: 5000, - }); - console.log(error); - }} - /> - - - ); -}; diff --git a/apps/frontend/src/components/accounts/CreateAccountForm/CreateAccountForm.tsx b/apps/frontend/src/components/accounts/CreateAccountForm/CreateAccountForm.tsx deleted file mode 100644 index 93a28834..00000000 --- a/apps/frontend/src/components/accounts/CreateAccountForm/CreateAccountForm.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import Box from "@mui/joy/Box"; -import Divider from "@mui/joy/Divider"; -import type { FC } from "react"; -import React, { useEffect } from "react"; -import { ExchangeCode } from "@opentrader/types"; -import { Form } from "react-final-form"; -import type { FormApi } from "final-form"; -import Grid from "@mui/joy/Grid"; -import Button from "@mui/joy/Button"; -import { tClient } from "src/lib/trpc/client"; -import { AccountNameField } from "./fields/AccountNameField"; -import { ApiKeyField } from "./fields/ApiKeyField"; -import type { CreateExchangeAccountFormValues } from "./types"; -import { ExchangeCodeField } from "./fields/ExchangeCodeField"; -import { IsDemoAccountField } from "./fields/IsDemoAccountField"; -import { PassphraseField } from "./fields/PassphraseField"; -import { SecretKeyField } from "./fields/SecretKeyField"; - -type CreateAccountFormProps = { - onCreated: () => void; - onError: (error?: unknown) => void; - debug?: boolean; -}; - -export const CreateAccountForm: FC = (props) => { - const { onCreated, onError, debug } = props; - - const { mutateAsync, isLoading, isSuccess, isError, error } = - tClient.exchangeAccount.create.useMutation(); - - useEffect(() => { - if (isSuccess) { - onCreated(); - } - }, [isSuccess]); - - useEffect(() => { - if (isError) { - onError(error); - } - }, [isError]); - - const initialValues: CreateExchangeAccountFormValues = { - // account - name: "", - exchangeCode: ExchangeCode.OKX, - - // credentials - apiKey: "", - secretKey: "", - password: "", - isDemoAccount: false, - }; - - const handleSubmit = async ( - values: CreateExchangeAccountFormValues, - form: FormApi, - ) => { - const data = await mutateAsync(values); - form.reset(); - - return data; - }; - - const validate = ( - values: CreateExchangeAccountFormValues, - ): - | Partial> - | undefined => { - if (!values.exchangeCode) { - return { exchangeCode: "Required" }; - } - - if (!values.name) { - return { name: "Required" }; - } - - if (!values.apiKey) { - return { apiKey: "Required" }; - } - - if (!values.secretKey) { - return { secretKey: "Required" }; - } - }; - - return ( - - - initialValues={initialValues} - onSubmit={handleSubmit} - render={({ handleSubmit, submitting, values, hasValidationErrors }) => ( -
void handleSubmit()}> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {debug ?
{JSON.stringify(values, null, 2)}
: null} -
- )} - validate={validate} - /> -
- ); -}; diff --git a/apps/frontend/src/components/accounts/CreateAccountForm/UpdateAccountForm.tsx b/apps/frontend/src/components/accounts/CreateAccountForm/UpdateAccountForm.tsx deleted file mode 100644 index 9bbd69d0..00000000 --- a/apps/frontend/src/components/accounts/CreateAccountForm/UpdateAccountForm.tsx +++ /dev/null @@ -1,155 +0,0 @@ -import Button from "@mui/joy/Button"; -import type { FC } from "react"; -import React, { useEffect } from "react"; -import { Form } from "react-final-form"; -import type { FormApi } from "final-form"; -import Box from "@mui/joy/Box"; -import Grid from "@mui/joy/Grid"; -import Divider from "@mui/joy/Divider"; -import { tClient } from "src/lib/trpc/client"; -import type { TExchangeAccount } from "src/types/trpc"; -import { AccountIdField } from "./fields/AccountIdField"; -import { AccountNameField } from "./fields/AccountNameField"; -import { ApiKeyField } from "./fields/ApiKeyField"; -import type { UpdateExchangeAccountFormValues } from "./types"; -import { ExchangeCodeField } from "./fields/ExchangeCodeField"; -import { IsDemoAccountField } from "./fields/IsDemoAccountField"; -import { PassphraseField } from "./fields/PassphraseField"; -import { SecretKeyField } from "./fields/SecretKeyField"; - -type UpdateAccountFormProps = { - onUpdated: () => void; - onError: (error?: unknown) => void; - account: TExchangeAccount; - debug?: boolean; -}; - -export const UpdateAccountForm: FC = (props) => { - const { onUpdated, onError, account, debug } = props; - - const { mutateAsync, isLoading, isSuccess, isError, error } = - tClient.exchangeAccount.update.useMutation(); - - useEffect(() => { - if (isSuccess) { - onUpdated(); - } - }, [isSuccess]); - - useEffect(() => { - if (isError) { - onError(error); - } - }, [isError]); - - const initialValues: UpdateExchangeAccountFormValues = { - // account - name: account.name, - exchangeCode: account.exchangeCode, - - // credentials - apiKey: account.apiKey, - secretKey: account.secretKey, - password: account.password, - isDemoAccount: account.isDemoAccount, - }; - - const handleSubmit = async ( - values: UpdateExchangeAccountFormValues, - _form: FormApi, - ) => { - const data = await mutateAsync({ - id: account.id, - body: values, - }); - - return data; - }; - - const validate = ( - values: UpdateExchangeAccountFormValues, - ): - | Partial> - | undefined => { - if (!values.exchangeCode) { - return { exchangeCode: "Required" }; - } - - if (!values.name) { - return { name: "Required" }; - } - - if (!values.apiKey) { - return { apiKey: "Required" }; - } - - if (!values.secretKey) { - return { secretKey: "Required" }; - } - - if (!values.password) { - return { password: "Required" }; - } - }; - - return ( - - - initialValues={initialValues} - onSubmit={handleSubmit} - render={({ handleSubmit, submitting, values, hasValidationErrors }) => ( -
void handleSubmit()}> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {debug ?
{JSON.stringify(values, null, 2)}
: null} -
- )} - validate={validate} - /> -
- ); -}; diff --git a/apps/frontend/src/components/accounts/CreateAccountForm/fields/AccountIdField.tsx b/apps/frontend/src/components/accounts/CreateAccountForm/fields/AccountIdField.tsx deleted file mode 100644 index e97d7f02..00000000 --- a/apps/frontend/src/components/accounts/CreateAccountForm/fields/AccountIdField.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import type { FC } from "react"; -import React from "react"; -import FormControl from "@mui/joy/FormControl"; -import FormLabel from "@mui/joy/FormLabel"; -import Input from "@mui/joy/Input"; - -type AccountIdFieldProps = { - disabled?: boolean; - value: number; -}; - -export const AccountIdField: FC = (props) => { - const { disabled, value } = props; - - return ( - - Account ID - - - - ); -}; diff --git a/apps/frontend/src/components/accounts/CreateAccountForm/fields/AccountNameField.tsx b/apps/frontend/src/components/accounts/CreateAccountForm/fields/AccountNameField.tsx deleted file mode 100644 index 64a7a968..00000000 --- a/apps/frontend/src/components/accounts/CreateAccountForm/fields/AccountNameField.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import type { FC } from "react"; -import React from "react"; -import FormControl from "@mui/joy/FormControl"; -import FormLabel from "@mui/joy/FormLabel"; -import Input from "@mui/joy/Input"; -import { Field } from "react-final-form"; -import type { CreateExchangeAccountFormValues } from "../types"; - -const fieldName: keyof CreateExchangeAccountFormValues = "name"; - -export const AccountNameField: FC = () => { - return ( - name={fieldName}> - {({ input }) => ( - - Account name - - - - )} - - ); -}; diff --git a/apps/frontend/src/components/accounts/CreateAccountForm/fields/ApiKeyField.tsx b/apps/frontend/src/components/accounts/CreateAccountForm/fields/ApiKeyField.tsx deleted file mode 100644 index 8940027b..00000000 --- a/apps/frontend/src/components/accounts/CreateAccountForm/fields/ApiKeyField.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import FormControl from "@mui/joy/FormControl"; -import FormLabel from "@mui/joy/FormLabel"; -import Input from "@mui/joy/Input"; -import type { FC } from "react"; -import React from "react"; -import { Field } from "react-final-form"; -import type { CreateExchangeAccountFormValues } from "../types"; - -const fieldName: keyof CreateExchangeAccountFormValues = "apiKey"; - -export const ApiKeyField: FC = () => { - return ( - name={fieldName}> - {({ input }) => ( - - API Key - - - - )} - - ); -}; diff --git a/apps/frontend/src/components/accounts/CreateAccountForm/fields/ExchangeCodeField.tsx b/apps/frontend/src/components/accounts/CreateAccountForm/fields/ExchangeCodeField.tsx deleted file mode 100644 index ce568005..00000000 --- a/apps/frontend/src/components/accounts/CreateAccountForm/fields/ExchangeCodeField.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { ExchangeCode } from "@opentrader/types"; -import React from "react"; -import Select from "@mui/joy/Select"; -import Option from "@mui/joy/Option"; -import { Field } from "react-final-form"; -import type { CreateExchangeAccountFormValues } from "../types"; - -const fieldName: keyof CreateExchangeAccountFormValues = "exchangeCode"; - -const exchangeCodes = Object.values(ExchangeCode); - -export function ExchangeCodeField() { - return ( - name={fieldName}> - {({ input }) => ( - - )} - - ); -} diff --git a/apps/frontend/src/components/accounts/CreateAccountForm/fields/IsDemoAccountField.tsx b/apps/frontend/src/components/accounts/CreateAccountForm/fields/IsDemoAccountField.tsx deleted file mode 100644 index 373a8de7..00000000 --- a/apps/frontend/src/components/accounts/CreateAccountForm/fields/IsDemoAccountField.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import type { FC } from "react"; -import React from "react"; -import Checkbox from "@mui/joy/Checkbox"; -import { Field } from "react-final-form"; -import type { CreateExchangeAccountFormValues } from "../types"; - -const fieldName: keyof CreateExchangeAccountFormValues = "isDemoAccount"; - -export const IsDemoAccountField: FC = () => { - return ( - - {({ input }) => ( - - )} - - ); -}; diff --git a/apps/frontend/src/components/accounts/CreateAccountForm/fields/PassphraseField.tsx b/apps/frontend/src/components/accounts/CreateAccountForm/fields/PassphraseField.tsx deleted file mode 100644 index 7a9d61ec..00000000 --- a/apps/frontend/src/components/accounts/CreateAccountForm/fields/PassphraseField.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import FormControl from "@mui/joy/FormControl"; -import FormLabel from "@mui/joy/FormLabel"; -import Input from "@mui/joy/Input"; -import type { FC } from "react"; -import React from "react"; -import { Field } from "react-final-form"; -import type { CreateExchangeAccountFormValues } from "../types"; - -const fieldName: keyof CreateExchangeAccountFormValues = "password"; - -export const PassphraseField: FC = () => { - return ( - name={fieldName}> - {({ input }) => ( - - Password - - - - )} - - ); -}; diff --git a/apps/frontend/src/components/accounts/CreateAccountForm/fields/SecretKeyField.tsx b/apps/frontend/src/components/accounts/CreateAccountForm/fields/SecretKeyField.tsx deleted file mode 100644 index 3e00f591..00000000 --- a/apps/frontend/src/components/accounts/CreateAccountForm/fields/SecretKeyField.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import FormControl from "@mui/joy/FormControl"; -import FormLabel from "@mui/joy/FormLabel"; -import Input from "@mui/joy/Input"; -import type { FC } from "react"; -import React from "react"; -import { Field } from "react-final-form"; -import type { CreateExchangeAccountFormValues } from "../types"; - -const fieldName: keyof CreateExchangeAccountFormValues = "secretKey"; - -export const SecretKeyField: FC = () => { - return ( - name={fieldName}> - {({ input }) => ( - - Secret key - - - - )} - - ); -}; diff --git a/apps/frontend/src/components/accounts/CreateAccountForm/types.ts b/apps/frontend/src/components/accounts/CreateAccountForm/types.ts deleted file mode 100644 index 679a284b..00000000 --- a/apps/frontend/src/components/accounts/CreateAccountForm/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { RouterInput } from "src/lib/trpc/types"; - -export type CreateExchangeAccountFormValues = - RouterInput["exchangeAccount"]["create"]; - -export type UpdateExchangeAccountFormValues = - RouterInput["exchangeAccount"]["update"]["body"]; diff --git a/apps/frontend/src/components/accounts/UpdateAccountDialog/UpdateAccountDialog.tsx b/apps/frontend/src/components/accounts/UpdateAccountDialog/UpdateAccountDialog.tsx deleted file mode 100644 index b7cc46f0..00000000 --- a/apps/frontend/src/components/accounts/UpdateAccountDialog/UpdateAccountDialog.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { FC } from "react"; -import React from "react"; -import Modal from "@mui/joy/Modal"; -import ModalDialog from "@mui/joy/ModalDialog"; -import DialogTitle from "@mui/joy/DialogTitle"; -import type { TExchangeAccount } from "src/types/trpc"; -import { useSnackbar } from "src/ui/snackbar"; -import { UpdateAccountForm } from "../CreateAccountForm/UpdateAccountForm"; - -type UpdateAccountDialogProps = { - open: boolean; - onClose: () => void; - onCreated: () => void; - account: TExchangeAccount; -}; - -export const UpdateAccountDialog: FC = (props) => { - const { open, onClose, onCreated, account } = props; - const { showSnackbar } = useSnackbar(); - - return ( - - - Edit exchange account - - { - showSnackbar(JSON.stringify(error), { - color: "danger", - }); - console.log(error); - }} - onUpdated={() => { - onCreated(); - onClose(); - - showSnackbar("Account updated"); - }} - /> - - - ); -}; diff --git a/apps/frontend/src/components/accounts/loading.tsx b/apps/frontend/src/components/accounts/loading.tsx deleted file mode 100644 index 21f29931..00000000 --- a/apps/frontend/src/components/accounts/loading.tsx +++ /dev/null @@ -1,24 +0,0 @@ -"use client"; - -import Box from "@mui/joy/Box"; -import Skeleton from "@mui/joy/Skeleton"; - -export default function Loading() { - return ( - - - - ); -} diff --git a/apps/frontend/src/components/accounts/page.tsx b/apps/frontend/src/components/accounts/page.tsx deleted file mode 100644 index 3a7a7f62..00000000 --- a/apps/frontend/src/components/accounts/page.tsx +++ /dev/null @@ -1,54 +0,0 @@ -"use client"; - -import Box from "@mui/joy/Box"; -import React, { useState } from "react"; -import { AccountsListTable } from "src/components/accounts/AccountsListTable"; -import { CreateAccountDialog } from "src/components/accounts/CreateAccountDialog/CreateAccountDialog"; -import { UpdateAccountDialog } from "src/components/accounts/UpdateAccountDialog/UpdateAccountDialog"; -import { tClient } from "src/lib/trpc/client"; -import type { TExchangeAccount } from "src/types/trpc"; - -export default function AccountsPage() { - const [createDialogOpen, setCreateDialogOpen] = useState(false); - const [updateDialogOpen, setUpdateDialogOpen] = useState(false); - - const [selectedAccount, setSelectedAccount] = - useState(null); - - const [exchangeAccounts, { refetch }] = - tClient.exchangeAccount.list.useSuspenseQuery(); - - return ( - - { - setCreateDialogOpen(true); - }} - onEditAccountClick={(account) => { - setSelectedAccount(account); - setUpdateDialogOpen(true); - }} - /> - - { - setCreateDialogOpen(false); - }} - onCreated={() => void refetch()} - open={createDialogOpen} - /> - - {selectedAccount ? ( - { - setUpdateDialogOpen(false); - }} - onCreated={() => void refetch()} - open={updateDialogOpen} - /> - ) : null} - - ); -} diff --git a/apps/frontend/src/components/bot/bot-details/BotActions/RunBotTemplateButton.tsx b/apps/frontend/src/components/bot/bot-details/BotActions/RunBotTemplateButton.tsx deleted file mode 100644 index 507cfd3c..00000000 --- a/apps/frontend/src/components/bot/bot-details/BotActions/RunBotTemplateButton.tsx +++ /dev/null @@ -1,48 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React from "react"; -import clsx from "clsx"; -import Button from "@mui/joy/Button"; -import { tClient } from "src/lib/trpc/client"; -import type { TGridBot } from "src/types/trpc"; -import { useSnackbar } from "src/ui/snackbar"; - -const componentName = "RunBotTemplateButton"; -const classes = { - root: `${componentName}-root`, -}; - -type RunBotTemplateButtonProps = { - className?: string; - bot: TGridBot; -}; - -export const RunBotTemplateButton: FC = (props) => { - const { className, bot } = props; - const { showSnackbar } = useSnackbar(); - - const { isLoading, mutate } = tClient.bot.manualProcess.useMutation({ - onSuccess() { - showSnackbar("Bot template executed"); - }, - }); - - return ( - - ); -}; diff --git a/apps/frontend/src/components/bot/bot-details/BotChart/BotChart.tsx b/apps/frontend/src/components/bot/bot-details/BotChart/BotChart.tsx deleted file mode 100644 index fc160406..00000000 --- a/apps/frontend/src/components/bot/bot-details/BotChart/BotChart.tsx +++ /dev/null @@ -1,71 +0,0 @@ -"use client"; - -import Skeleton from "@mui/joy/Skeleton"; -import { composeSymbolId } from "@opentrader/tools"; -import type { FC } from "react"; -import React, { Suspense, useState } from "react"; -import type { BarSize } from "@opentrader/types"; -import { tClient } from "src/lib/trpc/client"; -import { Chart, CHART_HEIGHT } from "src/ui/charts/Chart"; -import { FlexSpacer } from "src/ui/FlexSpacer"; -import { ExchangeAccountSelect } from "src/ui/selects/ExchangeAccountSelect"; -import { SymbolSelect } from "src/ui/selects/SymbolSelect"; -import { BarSizeSelect } from "src/ui/selects/BarSizeSelect"; - -const timeframes = ["1d", "4h", "1h", "5m", "1m"] as const; -export type ChartBarSize = Extract; - -type BotChartProps = { - botId: number; -}; - -const NOOP = () => void 0; - -export const BotChart: FC = ({ botId }) => { - const [bot] = tClient.bot.getOne.useSuspenseQuery(botId); - const [exchangeAccount] = tClient.exchangeAccount.getOne.useSuspenseQuery( - bot.exchangeAccountId, - ); - const [symbol] = tClient.symbol.getOne.useSuspenseQuery({ - symbolId: composeSymbolId( - exchangeAccount.exchangeCode, - bot.baseCurrency, - bot.quoteCurrency, - ), - }); - - const [barSize, setBarSize] = useState("1h"); - - return ( - - } - > - - - - - - { - setBarSize(value); - }} - value={barSize} - whitelist={timeframes} - /> - - - - - ); -}; diff --git a/apps/frontend/src/components/bot/bot-details/BotChart/index.ts b/apps/frontend/src/components/bot/bot-details/BotChart/index.ts deleted file mode 100644 index 0e3e0ca7..00000000 --- a/apps/frontend/src/components/bot/bot-details/BotChart/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./BotChart"; diff --git a/apps/frontend/src/components/bot/bot-details/BotSettings/BotSettings.tsx b/apps/frontend/src/components/bot/bot-details/BotSettings/BotSettings.tsx deleted file mode 100644 index 755ead64..00000000 --- a/apps/frontend/src/components/bot/bot-details/BotSettings/BotSettings.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import Chip from "@mui/joy/Chip"; -import List from "@mui/joy/List"; -import ListDivider from "@mui/joy/ListDivider"; -import type { FC } from "react"; -import DataObjectIcon from "@mui/icons-material/DataObject"; -import type { TBot } from "src/types/trpc"; -import { StatusSettingsListItem } from "src/components/common/bot/settings/StatusSettingListItem"; -import { PairSettingListItem } from "src/components/common/bot/settings/PairSettingListItem"; -import { SettingListItem } from "src/components/common/bot/settings/SettingListItem"; - -type BotSettingsProps = { - bot: TBot; -}; - -export const BotSettings: FC = ({ bot }) => { - return ( - - - - - - - - - - } name="Template"> - - {bot.template} - - - - ); -}; diff --git a/apps/frontend/src/components/bot/bot-details/BotSettings/BotSettingsCard.tsx b/apps/frontend/src/components/bot/bot-details/BotSettings/BotSettingsCard.tsx deleted file mode 100644 index 7892af47..00000000 --- a/apps/frontend/src/components/bot/bot-details/BotSettings/BotSettingsCard.tsx +++ /dev/null @@ -1,49 +0,0 @@ -"use client"; - -import Box from "@mui/joy/Box"; -import Card from "@mui/joy/Card"; -import Typography from "@mui/joy/Typography"; -import type { FC } from "react"; -import React from "react"; -import { SyncClosedOrdersButton } from "src/components/debug/SyncClosedOrdersButton"; -import { tClient } from "src/lib/trpc/client"; -import { BotAdditionalActions } from "src/components/common/bot/actions/BotAdditionalActions"; -import { RunBotTemplateButton } from "src/components/common/bot/actions/buttons/RunBotTemplateButton"; -import { StartStopBotButton } from "src/components/common/bot/actions/buttons/StartStopBotButton"; -import { DeleteBotButton } from "src/components/common/bot/actions/buttons/DeleteBotButton"; -import { BotActions } from "src/components/common/bot/actions/BotActions"; -import { BotSettings } from "./BotSettings"; - -type BotSettingsCardProps = { - botId: number; -}; - -export const BotSettingsCard: FC = ({ botId }) => { - const [bot] = tClient.bot.getOne.useSuspenseQuery(botId); - - return ( - - - - {bot.name} - - - - #{bot.id} - - - - - - - - - - - - - - - - ); -}; diff --git a/apps/frontend/src/components/bot/bot-details/BotSettings/index.ts b/apps/frontend/src/components/bot/bot-details/BotSettings/index.ts deleted file mode 100644 index 4052877a..00000000 --- a/apps/frontend/src/components/bot/bot-details/BotSettings/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./BotSettingsCard"; diff --git a/apps/frontend/src/components/bot/bot-details/BotSettingsForm/BotSettingsForm.tsx b/apps/frontend/src/components/bot/bot-details/BotSettingsForm/BotSettingsForm.tsx deleted file mode 100644 index 0cb805b9..00000000 --- a/apps/frontend/src/components/bot/bot-details/BotSettingsForm/BotSettingsForm.tsx +++ /dev/null @@ -1,45 +0,0 @@ -"use client"; - -import Button from "@mui/joy/Button"; -import { tClient } from "src/lib/trpc/client"; - -type Props = { - botId: number; -}; - -export function BotSettingsForm({ botId }: Props) { - const { data } = tClient.bot.getOne.useQuery(botId); - const { isLoading, mutate } = tClient.bot.update.useMutation(); - - const handleMutate = () => { - mutate({ - botId, - data: { - settings: { - template: { - name: "LowCapStrategy", - params: { - expectedDrop: 0.5, // 0.5% - }, - }, - symbols: ["BTC/USDT", "ETH/USDT", "UNI/USDT", "OKB/USDT"], - strategy: { - timeframe: "1m", - runOn: { - candleClosed: true, - orderFilled: true, - interval: 10000, - }, - }, - }, - }, - }); - }; - - return ( -
-
{JSON.stringify(data, null, 2)}
- -
- ); -} diff --git a/apps/frontend/src/components/bot/bot-details/loading.tsx b/apps/frontend/src/components/bot/bot-details/loading.tsx deleted file mode 100644 index 576db806..00000000 --- a/apps/frontend/src/components/bot/bot-details/loading.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import Grid from "@mui/joy/Grid"; -import Skeleton from "@mui/joy/Skeleton"; -import React from "react"; - -export default function Loading() { - return ( - - - - - - - - - - ); -} diff --git a/apps/frontend/src/components/bot/bot-details/page.tsx b/apps/frontend/src/components/bot/bot-details/page.tsx deleted file mode 100644 index f4555ba5..00000000 --- a/apps/frontend/src/components/bot/bot-details/page.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import Grid from "@mui/joy/Grid"; -import Skeleton from "@mui/joy/Skeleton"; -import React, { Suspense } from "react"; -import { ProfitsCard } from "src/components/common/smart-trades/ProfitsCard"; -import { CHART_HEIGHT } from "src/ui/charts/Chart"; -import { SmartTradesTable } from "src/components/common/smart-trades/SmartTradesTable"; -import { BotSettingsCard } from "./BotSettings/BotSettingsCard"; -import { BotChart } from "./BotChart"; - -type Props = { - botId: number; -}; - -export default function BotDetailsPage(props: Props) { - const { botId } = props; - - return ( - - - - } - > - - - - - - - } - > - - - - - - - } - > - - - - - - - } - > - - - - - ); -} diff --git a/apps/frontend/src/components/common/bot/BotStatusSwitcher.tsx b/apps/frontend/src/components/common/bot/BotStatusSwitcher.tsx deleted file mode 100644 index bd81de72..00000000 --- a/apps/frontend/src/components/common/bot/BotStatusSwitcher.tsx +++ /dev/null @@ -1,113 +0,0 @@ -"use client"; - -import FiberManualRecordIcon from "@mui/icons-material/FiberManualRecord"; -import type { SxProps } from "@mui/joy/styles/types"; -import type { FC } from "react"; -import React from "react"; -import clsx from "clsx"; -import type { ChipProps } from "@mui/joy/Chip"; -import Chip from "@mui/joy/Chip"; -import { styled } from "@mui/joy/styles"; -import { tClient } from "src/lib/trpc/client"; -import type { TBot } from "src/types/trpc"; -import { useSnackbar } from "src/ui/snackbar"; - -const componentName = "BotStatusChip"; -const classes = { - root: `${componentName}-root`, -}; -const StyledChip = styled(Chip)(() => ({ - /* Styles applied to the root element. */ - [`&.${classes.root}`]: {}, -})); - -type BotStatusSwitcherProps = { - className?: string; - bot: TBot; - sx?: SxProps; - size?: ChipProps["size"]; -}; - -export const BotStatusSwitcher: FC = (props) => { - const { className, bot, sx, size } = props; - const { showSnackbar } = useSnackbar(); - const tUtils = tClient.useUtils(); - - const invalidateState = () => { - // workaround, until refactored to one endpoint - void tUtils.gridBot.getOne.invalidate(bot.id); - void tUtils.bot.getOne.invalidate(bot.id); - - void tUtils.bot.activeSmartTrades.invalidate({ botId: bot.id }); - void tUtils.bot.completedSmartTrades.invalidate({ botId: bot.id }); - }; - - const startBot = tClient.bot.start.useMutation({ - onSuccess() { - invalidateState(); - - showSnackbar("Bot has been enabled"); - }, - }); - - const stopBot = tClient.bot.stop.useMutation({ - onSuccess() { - invalidateState(); - - showSnackbar("Bot has been stopped"); - }, - }); - - if (startBot.isLoading || stopBot.isLoading) { - return ( - } - sx={sx} - variant="outlined" - > - {startBot.isLoading ? "Starting..." : "Stopping..."} - - ); - } - - if (bot.enabled) { - return ( - { - stopBot.mutate({ - botId: bot.id, - }); - }} - size={size} - startDecorator={} - sx={sx} - variant="outlined" - > - Running - - ); - } - - return ( - { - startBot.mutate({ - botId: bot.id, - }); - }} - size={size} - startDecorator={} - sx={sx} - variant="outlined" - > - Disabled - - ); -}; diff --git a/apps/frontend/src/components/common/bot/actions/BotActions.tsx b/apps/frontend/src/components/common/bot/actions/BotActions.tsx deleted file mode 100644 index d57c7ab6..00000000 --- a/apps/frontend/src/components/common/bot/actions/BotActions.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import type { FC, ReactNode } from "react"; - -type BotActionsProps = { - children: ReactNode; -}; - -export const BotActions: FC = ({ children }) => { - return <>{children}; -}; diff --git a/apps/frontend/src/components/common/bot/actions/BotAdditionalActions.tsx b/apps/frontend/src/components/common/bot/actions/BotAdditionalActions.tsx deleted file mode 100644 index a0684c79..00000000 --- a/apps/frontend/src/components/common/bot/actions/BotAdditionalActions.tsx +++ /dev/null @@ -1,54 +0,0 @@ -"use client"; - -import Accordion from "@mui/joy/Accordion"; -import AccordionGroup from "@mui/joy/AccordionGroup"; -import AccordionSummary, { - accordionSummaryClasses, -} from "@mui/joy/AccordionSummary"; -import AccordionDetails, { - accordionDetailsClasses, -} from "@mui/joy/AccordionDetails"; -import type { FC, ReactNode } from "react"; -import React from "react"; - -type BotAdditionalActionsProps = { - children: ReactNode; -}; - -export const BotAdditionalActions: FC = ({ - children, -}) => { - return ( - ({ - // maxWidth: 400, - mx: -2, - mb: -2, - borderRadius: "md", - [`& .${accordionSummaryClasses.button}`]: { - color: theme.vars.palette.text.tertiary, - }, - [`& .${accordionDetailsClasses.root}`]: { - backgroundColor: "transparent", - color: theme.vars.palette.text.primary, - border: 0, - }, - [`& .${accordionDetailsClasses.content}`]: { - gap: "0.75rem", - - [`&.${accordionDetailsClasses.expanded}`]: { - paddingBlock: "0.75rem", - }, - }, - })} - transition="0.2s" - variant="plain" - > - - More actions - {children} - - - ); -}; diff --git a/apps/frontend/src/components/common/bot/actions/buttons/CronPlacePendingOrderButton.tsx b/apps/frontend/src/components/common/bot/actions/buttons/CronPlacePendingOrderButton.tsx deleted file mode 100644 index f6b86bca..00000000 --- a/apps/frontend/src/components/common/bot/actions/buttons/CronPlacePendingOrderButton.tsx +++ /dev/null @@ -1,101 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React from "react"; -import clsx from "clsx"; -import Button from "@mui/joy/Button"; -import Tooltip from "@mui/joy/Tooltip"; -import { tClient } from "src/lib/trpc/client"; -import type { TGridBot, TPendingSmartTrade } from "src/types/trpc"; -import { useSnackbar } from "src/ui/snackbar"; - -const componentName = "CronPlacePendingOrderButton"; -const classes = { - root: `${componentName}-root`, -}; - -type CronPlacePendingOrderButtonProps = { - className?: string; - bot: TGridBot; - smartTrades?: TPendingSmartTrade[]; -}; - -function buildTooltipTable(smartTrades: TPendingSmartTrade[]) { - const SM_COLUMN_LENGTH = 5; - const LG_COLUMN_LENGTH = 12; - - const idColumn = "id".padEnd(SM_COLUMN_LENGTH); - const buyColumn = "buy".padEnd(LG_COLUMN_LENGTH); - const sellColumn = "sell".padEnd(LG_COLUMN_LENGTH); - const tableHead = `${idColumn} ${buyColumn} ${sellColumn}`; - - let tableBody = ""; - - for (const smartTrade of smartTrades) { - tableBody += "\n"; - - const id = smartTrade.id.toString().padEnd(SM_COLUMN_LENGTH); - const entryPrice = smartTrade.entryOrder - .price!.toString() - .padEnd(LG_COLUMN_LENGTH); - const tpPrice = smartTrade.takeProfitOrder - .price!.toString() - .padEnd(LG_COLUMN_LENGTH); - - tableBody += `${id} ${entryPrice} ${tpPrice}`; - } - - return `${tableHead}${tableBody}`; -} - -// @deprecated -export const CronPlacePendingOrderButton: FC< - CronPlacePendingOrderButtonProps -> = (props) => { - const { className, bot, smartTrades = [] } = props; - const { showSnackbar } = useSnackbar(); - - const { isLoading, mutate } = tClient.bot.cronPlaceLimitOrders.useMutation({ - onSuccess() { - showSnackbar("Orders has been placed"); - }, - }); - - const buttonNode = ( - - ); - - if (smartTrades.length > 0) { - return ( - {buildTooltipTable(smartTrades)}}> - {buttonNode} - - ); - } - - return ( - - ); -}; diff --git a/apps/frontend/src/components/common/bot/actions/buttons/DeleteBotButton.tsx b/apps/frontend/src/components/common/bot/actions/buttons/DeleteBotButton.tsx deleted file mode 100644 index 2e5836d9..00000000 --- a/apps/frontend/src/components/common/bot/actions/buttons/DeleteBotButton.tsx +++ /dev/null @@ -1,92 +0,0 @@ -"use client"; - -import { useRouter } from "next/navigation"; -import type { FC } from "react"; -import React from "react"; -import clsx from "clsx"; -import Button from "@mui/joy/Button"; -import { tClient } from "src/lib/trpc/client"; -import type { TBot } from "src/types/trpc"; -import { useConfirmationDialog } from "src/ui/confirmation-dialog"; -import { useSnackbar } from "src/ui/snackbar"; -import { toPage } from "src/utils/next/toPage"; - -const componentName = "DeleteBotButton"; -const classes = { - root: `${componentName}-root`, -}; - -type DeleteBotButtonProps = { - className?: string; - bot: TBot; -}; - -export const DeleteBotButton: FC = ({ - className, - bot, -}) => { - const router = useRouter(); - const { showSnackbar } = useSnackbar(); - const { showConfirmDialog } = useConfirmationDialog(); - const tUtils = tClient.useUtils(); - - const invalidateState = () => { - void tUtils.bot.list.invalidate(); - void tUtils.gridBot.list.invalidate(); - }; - - const deleteBot = tClient.bot.delete.useMutation({ - onSuccess() { - invalidateState(); - - showSnackbar("Bot has been deleted"); - - setTimeout(() => { - router.push(toPage("grid-bot")); - }, 1500); - }, - }); - - if (deleteBot.isLoading) { - return ( - - ); - } - - return ( - - ); -}; diff --git a/apps/frontend/src/components/common/bot/actions/buttons/RunBotTemplateButton.tsx b/apps/frontend/src/components/common/bot/actions/buttons/RunBotTemplateButton.tsx deleted file mode 100644 index 9eed0e11..00000000 --- a/apps/frontend/src/components/common/bot/actions/buttons/RunBotTemplateButton.tsx +++ /dev/null @@ -1,48 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React from "react"; -import clsx from "clsx"; -import Button from "@mui/joy/Button"; -import { tClient } from "src/lib/trpc/client"; -import type { TBot } from "src/types/trpc"; -import { useSnackbar } from "src/ui/snackbar"; - -const componentName = "RunBotTemplateButton"; -const classes = { - root: `${componentName}-root`, -}; - -type RunBotTemplateButtonProps = { - className?: string; - bot: TBot; -}; - -export const RunBotTemplateButton: FC = (props) => { - const { className, bot } = props; - const { showSnackbar } = useSnackbar(); - - const { isLoading, mutate } = tClient.bot.manualProcess.useMutation({ - onSuccess() { - showSnackbar("Bot template executed"); - }, - }); - - return ( - - ); -}; diff --git a/apps/frontend/src/components/common/bot/actions/buttons/StartStopBotButton.tsx b/apps/frontend/src/components/common/bot/actions/buttons/StartStopBotButton.tsx deleted file mode 100644 index 6c4dd5b0..00000000 --- a/apps/frontend/src/components/common/bot/actions/buttons/StartStopBotButton.tsx +++ /dev/null @@ -1,101 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React from "react"; -import clsx from "clsx"; -import Button from "@mui/joy/Button"; -import { tClient } from "src/lib/trpc/client"; -import type { TBot } from "src/types/trpc"; -import { useSnackbar } from "src/ui/snackbar"; - -const componentName = "StartStopBotButton"; -const classes = { - root: `${componentName}-root`, -}; - -type StartStopBotButtonProps = { - className?: string; - bot: TBot; -}; - -export const StartStopBotButton: FC = ({ - className, - bot, -}) => { - const { showSnackbar } = useSnackbar(); - const tUtils = tClient.useUtils(); - - const invalidateState = () => { - // workaround, until merged into one endpoint - void tUtils.gridBot.getOne.invalidate(bot.id); - void tUtils.bot.getOne.invalidate(bot.id); - - void tUtils.bot.activeSmartTrades.invalidate({ botId: bot.id }); - void tUtils.bot.completedSmartTrades.invalidate({ botId: bot.id }); - }; - - const startBot = tClient.bot.start.useMutation({ - onSuccess() { - invalidateState(); - - showSnackbar("Bot has been enabled"); - }, - }); - - const stopBot = tClient.bot.stop.useMutation({ - onSuccess() { - invalidateState(); - - showSnackbar("Bot has been stopped"); - }, - }); - - if (startBot.isLoading || stopBot.isLoading) { - return ( - - ); - } - - if (bot.enabled) { - return ( - - ); - } - - return ( - - ); -}; diff --git a/apps/frontend/src/components/common/bot/actions/buttons/SyncOrdersButton.tsx b/apps/frontend/src/components/common/bot/actions/buttons/SyncOrdersButton.tsx deleted file mode 100644 index 23d2a4af..00000000 --- a/apps/frontend/src/components/common/bot/actions/buttons/SyncOrdersButton.tsx +++ /dev/null @@ -1,49 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React from "react"; -import clsx from "clsx"; -import Button from "@mui/joy/Button"; -import { tClient } from "src/lib/trpc/client"; -import type { TBot } from "src/types/trpc"; -import { useSnackbar } from "src/ui/snackbar"; - -const componentName = "RunBotTemplateButton"; -const classes = { - root: `${componentName}-root`, -}; - -type SyncOrdersButtonProps = { - className?: string; - bot: TBot; -}; - -// @deprecated -export const SyncOrdersButton: FC = (props) => { - const { className, bot } = props; - const { showSnackbar } = useSnackbar(); - - const { isLoading, mutate } = tClient.bot.syncOrders.useMutation({ - onSuccess() { - showSnackbar("Orders have been synced"); - }, - }); - - return ( - - ); -}; diff --git a/apps/frontend/src/components/common/bot/settings/PairSettingListItem.tsx b/apps/frontend/src/components/common/bot/settings/PairSettingListItem.tsx deleted file mode 100644 index af9715e0..00000000 --- a/apps/frontend/src/components/common/bot/settings/PairSettingListItem.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import Box from "@mui/joy/Box"; -import ListItem from "@mui/joy/ListItem"; -import ListItemContent from "@mui/joy/ListItemContent"; -import ListItemDecorator from "@mui/joy/ListItemDecorator"; -import CurrencyBitcoinIcon from "@mui/icons-material/CurrencyBitcoin"; -import Typography from "@mui/joy/Typography"; -import type { FC } from "react"; -import { CryptoIcon } from "src/ui/icons/CryptoIcon"; -import type { TBot } from "src/types/trpc"; - -type PairSettingListItemProps = { - bot: TBot; -}; - -export const PairSettingListItem: FC = ({ bot }) => { - return ( - - - - - Pair - - - - - {bot.baseCurrency}/{bot.quoteCurrency} - - - - ); -}; diff --git a/apps/frontend/src/components/common/bot/settings/SettingListItem.tsx b/apps/frontend/src/components/common/bot/settings/SettingListItem.tsx deleted file mode 100644 index 205dc1b3..00000000 --- a/apps/frontend/src/components/common/bot/settings/SettingListItem.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import ListItem from "@mui/joy/ListItem"; -import ListItemContent from "@mui/joy/ListItemContent"; -import ListItemDecorator from "@mui/joy/ListItemDecorator"; -import Typography from "@mui/joy/Typography"; -import type { FC, ReactNode } from "react"; - -type SettingListItemProps = { - icon: ReactNode; - /** - * Option name - */ - name: string; - /** - * Option value - */ - children: ReactNode; -}; - -export const SettingListItem: FC = ({ - icon, - name, - children, -}) => { - return ( - - {icon} - {name} - {children} - - ); -}; diff --git a/apps/frontend/src/components/common/bot/settings/StatusSettingListItem.tsx b/apps/frontend/src/components/common/bot/settings/StatusSettingListItem.tsx deleted file mode 100644 index 615c4b32..00000000 --- a/apps/frontend/src/components/common/bot/settings/StatusSettingListItem.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import ListItem from "@mui/joy/ListItem"; -import ListItemContent from "@mui/joy/ListItemContent"; -import ListItemDecorator from "@mui/joy/ListItemDecorator"; -import CircleIcon from "@mui/icons-material/Circle"; -import type { FC } from "react"; -import { BotStatusSwitcher } from "src/components/common/bot/BotStatusSwitcher"; -import type { TBot } from "src/types/trpc"; - -type StatusSettingsListItemProps = { - bot: TBot; -}; - -export const StatusSettingsListItem: FC = ({ - bot, -}) => { - return ( - - - - - Status - - - - ); -}; diff --git a/apps/frontend/src/components/common/smart-trades/ProfitsCard/Profit.tsx b/apps/frontend/src/components/common/smart-trades/ProfitsCard/Profit.tsx deleted file mode 100644 index 66557ada..00000000 --- a/apps/frontend/src/components/common/smart-trades/ProfitsCard/Profit.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import Typography from "@mui/joy/Typography"; -import type { FC } from "react"; - -type ProfitProps = { - size?: "sm" | "md" | "lg"; - profit: number; - currency: string; -}; - -export const Profit: FC = ({ profit, currency, size = "md" }) => { - const isPositive = profit >= 0; - const sign = isPositive ? "+" : ""; - const color = isPositive - ? "var(--joy-palette-success-500)" - : "var(--joy-palette-danger-500)"; - - return ( - - {sign} - {profit.toFixed(2)} -   - {currency} - - ); -}; diff --git a/apps/frontend/src/components/common/smart-trades/ProfitsCard/ProfitDetails.tsx b/apps/frontend/src/components/common/smart-trades/ProfitsCard/ProfitDetails.tsx deleted file mode 100644 index 8e34e166..00000000 --- a/apps/frontend/src/components/common/smart-trades/ProfitsCard/ProfitDetails.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import type { FC } from "react"; -import Box from "@mui/joy/Box"; -import List from "@mui/joy/List"; -import ListItem from "@mui/joy/ListItem"; -import ListItemContent from "@mui/joy/ListItemContent"; -import Typography from "@mui/joy/Typography"; -import type { TCompletedSmartTrade } from "src/types/trpc"; -import { calcProfitFromSmartTrade } from "src/utils/smart-trades/calcProfitFromSmartTrade"; - -type ProfitDetailsProps = { - smartTrade: TCompletedSmartTrade; -}; - -export const ProfitDetails: FC = ({ smartTrade }) => { - const { id, entryOrder, takeProfitOrder } = smartTrade; - - const { fee } = calcProfitFromSmartTrade(smartTrade); - - return ( - - SmartTrade - - - ID - - {id} - - - - Qty - {takeProfitOrder.quantity} {smartTrade.baseCurrency} - - - - Buy - {entryOrder.filledPrice?.toFixed(2)} {smartTrade.quoteCurrency} - - - - Sell - {takeProfitOrder.filledPrice?.toFixed(2)} {smartTrade.quoteCurrency} - - - - Fee - {fee.toFixed(2)} {smartTrade.quoteCurrency} - - - - ); -}; diff --git a/apps/frontend/src/components/common/smart-trades/ProfitsCard/ProfitItem.tsx b/apps/frontend/src/components/common/smart-trades/ProfitsCard/ProfitItem.tsx deleted file mode 100644 index 27d37553..00000000 --- a/apps/frontend/src/components/common/smart-trades/ProfitsCard/ProfitItem.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import type { FC } from "react"; -import React from "react"; -import Typography from "@mui/joy/Typography"; -import formatDistanceToNow from "date-fns/formatDistanceToNow"; -import ListItemContent from "@mui/joy/ListItemContent"; -import ListItem from "@mui/joy/ListItem"; -import ListItemDecorator from "@mui/joy/ListItemDecorator"; -import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; -import Tooltip from "@mui/joy/Tooltip"; -import type { TCompletedSmartTrade } from "src/types/trpc"; -import { formatDateTime } from "src/utils/date/formatDateTime"; -import { calcProfitFromSmartTrade } from "src/utils/smart-trades/calcProfitFromSmartTrade"; -import { ProfitDetails } from "./ProfitDetails"; -import { Profit } from "./Profit"; - -type ProfitItemProps = { - smartTrade: TCompletedSmartTrade; -}; - -export const ProfitItem: FC = ({ smartTrade }) => { - const { netProfit } = calcProfitFromSmartTrade(smartTrade); - - const { filledAt } = smartTrade.takeProfitOrder; - const dateLabel = filledAt - ? formatDateTime(filledAt.getTime()) - : "Missing date"; - - return ( - - - - - - - - - - {filledAt ? formatDistanceToNow(filledAt) : "Missing date"} - - - - }> - - - - ); -}; diff --git a/apps/frontend/src/components/common/smart-trades/ProfitsCard/ProfitsCard.tsx b/apps/frontend/src/components/common/smart-trades/ProfitsCard/ProfitsCard.tsx deleted file mode 100644 index 1a184227..00000000 --- a/apps/frontend/src/components/common/smart-trades/ProfitsCard/ProfitsCard.tsx +++ /dev/null @@ -1,71 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React from "react"; -import Box from "@mui/joy/Box"; -import Card from "@mui/joy/Card"; -import CardContent from "@mui/joy/CardContent"; -import ListDivider from "@mui/joy/ListDivider"; -import Tooltip from "@mui/joy/Tooltip"; -import Typography from "@mui/joy/Typography"; -import List from "@mui/joy/List"; -import { tClient } from "src/lib/trpc/client"; -import { calcTotalProfitFromSmartTrades } from "src/utils/smart-trades/calcTotalProfitFromSmartTrades"; -import { ProfitItem } from "./ProfitItem"; -import { Profit } from "./Profit"; - -type ProfitsCardProps = { - botId: number; -}; - -export const ProfitsCard: FC = ({ botId }) => { - const [bot] = tClient.bot.getOne.useSuspenseQuery(botId); - const [smartTrades] = tClient.bot.completedSmartTrades.useSuspenseQuery({ - botId, - }); - - const totalProfit = calcTotalProfitFromSmartTrades(smartTrades); - - return ( - - - - Profits - - - {smartTrades.length > 0 ? ( - - - - - - ) : null} - - - {smartTrades.length > 0 ? ( - - - {smartTrades.map((smartTrade, i) => ( - - - {i < smartTrades.length - 1 ? : null} - - ))} - - - ) : ( - - No profits yet - - )} - - ); -}; diff --git a/apps/frontend/src/components/common/smart-trades/ProfitsCard/index.ts b/apps/frontend/src/components/common/smart-trades/ProfitsCard/index.ts deleted file mode 100644 index 8e5ad82c..00000000 --- a/apps/frontend/src/components/common/smart-trades/ProfitsCard/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./ProfitsCard"; diff --git a/apps/frontend/src/components/common/smart-trades/SmartTradesTable/NoActiveSmartTradesPlaceholder.tsx b/apps/frontend/src/components/common/smart-trades/SmartTradesTable/NoActiveSmartTradesPlaceholder.tsx deleted file mode 100644 index ab459477..00000000 --- a/apps/frontend/src/components/common/smart-trades/SmartTradesTable/NoActiveSmartTradesPlaceholder.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import Typography from "@mui/joy/Typography"; - -export function NoActiveSmartTradesPlaceholder() { - return ( - - - - - No active SmartTrades. Please start the bot. - - - - - ); -} diff --git a/apps/frontend/src/components/common/smart-trades/SmartTradesTable/SmartTradeStatus.tsx b/apps/frontend/src/components/common/smart-trades/SmartTradesTable/SmartTradeStatus.tsx deleted file mode 100644 index e0334556..00000000 --- a/apps/frontend/src/components/common/smart-trades/SmartTradesTable/SmartTradeStatus.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import Chip from "@mui/joy/Chip"; -import type { FC } from "react"; -import type { TActiveSmartTrade } from "src/types/trpc"; - -type SmartTradeStatusProps = { - smartTrade: TActiveSmartTrade; -}; - -export const SmartTradeStatus: FC = ({ smartTrade }) => { - const isPositionOpen = smartTrade.entryOrder.status === "Filled"; - - if (isPositionOpen) { - return ( - - Selling - - ); - } - - return ( - - Buying - - ); -}; diff --git a/apps/frontend/src/components/common/smart-trades/SmartTradesTable/SmartTradesTable.tsx b/apps/frontend/src/components/common/smart-trades/SmartTradesTable/SmartTradesTable.tsx deleted file mode 100644 index c192e5a7..00000000 --- a/apps/frontend/src/components/common/smart-trades/SmartTradesTable/SmartTradesTable.tsx +++ /dev/null @@ -1,57 +0,0 @@ -"use client"; - -import Sheet from "@mui/joy/Sheet"; -import Table from "@mui/joy/Table"; -import type { FC } from "react"; -import { tClient } from "src/lib/trpc/client"; -import { SmartTradesTableHead } from "src/components/common/smart-trades/SmartTradesTable/SmartTradesTableHead"; -import { SmartTradesTableItem } from "src/components/common/smart-trades/SmartTradesTable/SmartTradesTableItem"; -import { NoActiveSmartTradesPlaceholder } from "src/components/common/smart-trades/SmartTradesTable/NoActiveSmartTradesPlaceholder"; - -type SmartTradesTableProps = { - botId: number; -}; - -export const SmartTradesTable: FC = ({ botId }) => { - const [smartTrades] = tClient.bot.activeSmartTrades.useSuspenseQuery({ - botId, - }); - - return ( - - - theme.vars.palette.success.softBg, - "& thead th:nth-child(1)": { - width: "40px", - }, - "& thead th:nth-child(2)": { - width: "30%", - }, - "& tr > *:nth-child(n+3)": { textAlign: "right" }, - }} - > - - - {smartTrades.length > 0 ? ( - - {smartTrades.map((smartTrade) => ( - - ))} - - ) : ( - - )} -
-
- ); -}; diff --git a/apps/frontend/src/components/common/smart-trades/SmartTradesTable/SmartTradesTableHead.tsx b/apps/frontend/src/components/common/smart-trades/SmartTradesTable/SmartTradesTableHead.tsx deleted file mode 100644 index 5a79945c..00000000 --- a/apps/frontend/src/components/common/smart-trades/SmartTradesTable/SmartTradesTableHead.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import type { FC } from "react"; -import { ID_COLUMN_MIN_WIDTH } from "src/components/common/smart-trades/SmartTradesTable/constants"; - -export const SmartTradesTableHead: FC = () => { - return ( - - - - ID - - - Quantity - - Price - Status - Orders status - Amount - Created - Ref - - - ); -}; diff --git a/apps/frontend/src/components/common/smart-trades/SmartTradesTable/SmartTradesTableItem.tsx b/apps/frontend/src/components/common/smart-trades/SmartTradesTable/SmartTradesTableItem.tsx deleted file mode 100644 index bb1b2fab..00000000 --- a/apps/frontend/src/components/common/smart-trades/SmartTradesTable/SmartTradesTableItem.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import List from "@mui/joy/List"; -import ListItem from "@mui/joy/ListItem"; -import Tooltip from "@mui/joy/Tooltip"; -import Big from "big.js"; -import type { FC } from "react"; -import React from "react"; -import type { TActiveSmartTrade } from "src/types/trpc"; -import { formatDateTime } from "src/utils/date/formatDateTime"; -import { SmartTradeStatus } from "src/components/common/smart-trades/SmartTradesTable/SmartTradeStatus"; -import { ID_COLUMN_MIN_WIDTH } from "src/components/common/smart-trades/SmartTradesTable/constants"; - -type SmartTradeTableItemProps = { - smartTrade: TActiveSmartTrade; -}; - -export const SmartTradesTableItem: FC = ({ - smartTrade, -}) => { - const isPositionOpen = smartTrade.entryOrder.status === "Filled"; - const amount = new Big(smartTrade.entryOrder.price || 0) - .times(smartTrade.entryOrder.quantity) - .toFixed(2) - .toString(); - const createdAt = formatDateTime(new Date(smartTrade.createdAt).getTime()); - const { entryOrder, takeProfitOrder } = smartTrade; - const price = isPositionOpen ? takeProfitOrder.price : entryOrder.price; - - return ( - - - - - Entry Order ID: {entryOrder.id}: - {entryOrder.exchangeOrderId ?? "null"} - - - TP Order ID: {takeProfitOrder.id}: - {takeProfitOrder.exchangeOrderId} - - - } - > -
{smartTrade.id}
-
- - - {smartTrade.entryOrder.quantity} {smartTrade.baseCurrency} - - - - - {price} {smartTrade.quoteCurrency} - - - - - - - -
- {smartTrade.entryOrder.status} - / - {smartTrade.takeProfitOrder.status} -
- - - {" "} - {amount} {smartTrade.quoteCurrency} - - {createdAt} - {smartTrade.ref} - - ); -}; diff --git a/apps/frontend/src/components/common/smart-trades/SmartTradesTable/constants.ts b/apps/frontend/src/components/common/smart-trades/SmartTradesTable/constants.ts deleted file mode 100644 index feafd191..00000000 --- a/apps/frontend/src/components/common/smart-trades/SmartTradesTable/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const ID_COLUMN_MIN_WIDTH = 64; diff --git a/apps/frontend/src/components/common/smart-trades/SmartTradesTable/index.ts b/apps/frontend/src/components/common/smart-trades/SmartTradesTable/index.ts deleted file mode 100644 index a6d54242..00000000 --- a/apps/frontend/src/components/common/smart-trades/SmartTradesTable/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "src/components/common/smart-trades/SmartTradesTable/SmartTradesTable"; diff --git a/apps/frontend/src/components/debug/SyncClosedOrdersButton.tsx b/apps/frontend/src/components/debug/SyncClosedOrdersButton.tsx deleted file mode 100644 index c7e03243..00000000 --- a/apps/frontend/src/components/debug/SyncClosedOrdersButton.tsx +++ /dev/null @@ -1,62 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React, { useEffect } from "react"; -import clsx from "clsx"; -import Button from "@mui/joy/Button"; -import { tClient } from "src/lib/trpc/client"; -import { useSnackbar } from "src/ui/snackbar"; - -const componentName = "SyncClosedOrdersButton"; -const classes = { - root: `${componentName}-root`, -}; - -type SyncClosedOrdersButtonProps = { - className?: string; - polling?: boolean; -}; - -export const SyncClosedOrdersButton: FC = ( - props, -) => { - const { className, polling } = props; - const { showSnackbar } = useSnackbar(); - - const { isLoading, mutate, mutateAsync } = - tClient.cron.syncClosedOrders.useMutation({ - onSuccess() { - showSnackbar("Orders have been synced"); - }, - }); - - useEffect(() => { - if (!polling) return; - - const timer = setInterval(() => { - void mutateAsync().then((data) => { - console.log("response", data); - }); - }, 15000); - - return () => { - clearInterval(timer); - }; - }, [polling]); - - return ( - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/bot-details/BotSettings/BotSettings.tsx b/apps/frontend/src/components/grid-bot/bot-details/BotSettings/BotSettings.tsx deleted file mode 100644 index 17314a6b..00000000 --- a/apps/frontend/src/components/grid-bot/bot-details/BotSettings/BotSettings.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import DataObjectIcon from "@mui/icons-material/DataObject"; -import Chip from "@mui/joy/Chip"; -import List from "@mui/joy/List"; -import ListDivider from "@mui/joy/ListDivider"; -import type { FC } from "react"; -import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward"; -import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward"; -import FormatListNumberedRtlIcon from "@mui/icons-material/FormatListNumberedRtl"; -import NumbersIcon from "@mui/icons-material/Numbers"; -import type { TGridBot } from "src/types/trpc"; -import { calcAverageQuantityPerGrid } from "src/utils/grid-bot/calcAverageQuantityPerGrid"; -import { findHighestGridLinePrice } from "src/utils/grid-bot/findHighestGridLinePrice"; -import { findLowestGridLinePrice } from "src/utils/grid-bot/findLowestGridLinePrice"; -import { StatusSettingsListItem } from "src/components/common/bot/settings/StatusSettingListItem"; -import { PairSettingListItem } from "src/components/common/bot/settings/PairSettingListItem"; -import { SettingListItem } from "src/components/common/bot/settings/SettingListItem"; - -type BotSettingsProps = { - bot: TGridBot; -}; - -export const BotSettings: FC = ({ bot }) => { - const lowPrice = findLowestGridLinePrice(bot.settings.gridLines); - const highPrice = findHighestGridLinePrice(bot.settings.gridLines); - const averageQuantityPerGrid = calcAverageQuantityPerGrid( - bot.settings.gridLines, - ); - - return ( - - - - - - - - - - } name="High price"> - {highPrice} {bot.quoteCurrency} - - - - - } name="Low price"> - {lowPrice} {bot.quoteCurrency} - - - - - } name="Av. quantity per grid"> - {averageQuantityPerGrid.toFixed(6)} {bot.baseCurrency} - - - - - } name="Grid levels"> - {bot.settings.gridLines.length} - - - - - } name="Template"> - - {bot.template} - - - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/bot-details/BotSettings/BotSettingsCard.tsx b/apps/frontend/src/components/grid-bot/bot-details/BotSettings/BotSettingsCard.tsx deleted file mode 100644 index 7788dca4..00000000 --- a/apps/frontend/src/components/grid-bot/bot-details/BotSettings/BotSettingsCard.tsx +++ /dev/null @@ -1,49 +0,0 @@ -"use client"; - -import Box from "@mui/joy/Box"; -import Card from "@mui/joy/Card"; -import Typography from "@mui/joy/Typography"; -import type { FC } from "react"; -import React from "react"; -import { SyncClosedOrdersButton } from "src/components/debug/SyncClosedOrdersButton"; -import { tClient } from "src/lib/trpc/client"; -import { BotAdditionalActions } from "src/components/common/bot/actions/BotAdditionalActions"; -import { RunBotTemplateButton } from "src/components/common/bot/actions/buttons/RunBotTemplateButton"; -import { StartStopBotButton } from "src/components/common/bot/actions/buttons/StartStopBotButton"; -import { DeleteBotButton } from "src/components/common/bot/actions/buttons/DeleteBotButton"; -import { BotActions } from "src/components/common/bot/actions/BotActions"; -import { BotSettings } from "./BotSettings"; - -type BotSettingsCardProps = { - botId: number; -}; - -export const BotSettingsCard: FC = ({ botId }) => { - const [bot] = tClient.gridBot.getOne.useSuspenseQuery(botId); - - return ( - - - - {bot.name} - - - - #{bot.id} - - - - - - - - - - - - - - - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/bot-details/BotSettings/index.ts b/apps/frontend/src/components/grid-bot/bot-details/BotSettings/index.ts deleted file mode 100644 index 4052877a..00000000 --- a/apps/frontend/src/components/grid-bot/bot-details/BotSettings/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./BotSettingsCard"; diff --git a/apps/frontend/src/components/grid-bot/bot-details/GridBotSettings/GridBotSettings.tsx b/apps/frontend/src/components/grid-bot/bot-details/GridBotSettings/GridBotSettings.tsx deleted file mode 100644 index 549fd789..00000000 --- a/apps/frontend/src/components/grid-bot/bot-details/GridBotSettings/GridBotSettings.tsx +++ /dev/null @@ -1,56 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React from "react"; -import Grid from "@mui/joy/Grid"; -import Divider from "@mui/joy/Divider"; -import type { TGridBot, TSymbol } from "src/types/trpc"; -import { calcAverageQuantityPerGrid } from "src/utils/grid-bot/calcAverageQuantityPerGrid"; -import { findHighestGridLinePrice } from "src/utils/grid-bot/findHighestGridLinePrice"; -import { findLowestGridLinePrice } from "src/utils/grid-bot/findLowestGridLinePrice"; -import { SettingInput } from "./SettingInput"; - -type SimpleGridFormProps = { - bot: TGridBot; - symbol: TSymbol; -}; - -export const GridBotSettings: FC = ({ bot }) => { - const highPrice = findHighestGridLinePrice(bot.settings.gridLines); - const lowPrice = findLowestGridLinePrice(bot.settings.gridLines); - const averageQuantityPerGrid = calcAverageQuantityPerGrid( - bot.settings.gridLines, - ); - - return ( - - - Bot settings - - - - - - - - - - - - - - - - - - - - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/bot-details/GridBotSettings/SettingInput.tsx b/apps/frontend/src/components/grid-bot/bot-details/GridBotSettings/SettingInput.tsx deleted file mode 100644 index 9ac23ef9..00000000 --- a/apps/frontend/src/components/grid-bot/bot-details/GridBotSettings/SettingInput.tsx +++ /dev/null @@ -1,20 +0,0 @@ -"use client"; - -import FormControl from "@mui/joy/FormControl"; -import FormLabel from "@mui/joy/FormLabel"; -import Input from "@mui/joy/Input"; -import type { FC } from "react"; -import React from "react"; - -type SettingInputProps = { - label: string; - value: number; -}; - -export const SettingInput: FC = ({ value, label }) => ( - - {label} - - - -); diff --git a/apps/frontend/src/components/grid-bot/bot-details/GridBotSettings/index.ts b/apps/frontend/src/components/grid-bot/bot-details/GridBotSettings/index.ts deleted file mode 100644 index f81bed0d..00000000 --- a/apps/frontend/src/components/grid-bot/bot-details/GridBotSettings/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./GridBotSettings"; diff --git a/apps/frontend/src/components/grid-bot/bot-details/GridDetailChart/GridDetailChart.tsx b/apps/frontend/src/components/grid-bot/bot-details/GridDetailChart/GridDetailChart.tsx deleted file mode 100644 index 94c95c78..00000000 --- a/apps/frontend/src/components/grid-bot/bot-details/GridDetailChart/GridDetailChart.tsx +++ /dev/null @@ -1,109 +0,0 @@ -"use client"; - -import Box from "@mui/joy/Box"; -import Skeleton from "@mui/joy/Skeleton"; -import { composeSymbolId } from "@opentrader/tools"; -import type { FC } from "react"; -import React, { Suspense, useMemo, useState } from "react"; -import type { BarSize } from "@opentrader/types"; -import { tClient } from "src/lib/trpc/client"; -import { Chart, CHART_HEIGHT, ChartOptions } from "src/ui/charts/Chart"; -import { FlexSpacer } from "src/ui/FlexSpacer"; -import { ExchangeAccountSelect } from "src/ui/selects/ExchangeAccountSelect"; -import { SymbolSelect } from "src/ui/selects/SymbolSelect"; -import { BarSizeSelect } from "src/ui/selects/BarSizeSelect"; -import { computePriceLines } from "./utils/computePriceLines"; -import { computeTradeMarkers } from "./utils/computeTradeMarkers"; - -const timeframes = ["1d", "4h", "1h", "5m", "1m"] as const; -export type ChartBarSize = Extract; - -type GridChartProps = { - botId: number; -}; - -const NOOP = () => void 0; - -export const GridDetailChart: FC = ({ botId }) => { - const [bot] = tClient.gridBot.getOne.useSuspenseQuery(botId); - const [exchangeAccount] = tClient.exchangeAccount.getOne.useSuspenseQuery( - bot.exchangeAccountId, - ); - const [symbol] = tClient.symbol.getOne.useSuspenseQuery({ - symbolId: composeSymbolId( - exchangeAccount.exchangeCode, - bot.baseCurrency, - bot.quoteCurrency, - ), - }); - const [activeSmartTrades] = tClient.bot.activeSmartTrades.useSuspenseQuery({ - botId, - }); - const [completedSmartTrades] = - tClient.bot.completedSmartTrades.useSuspenseQuery({ - botId, - }); - - const priceLines = useMemo( - () => computePriceLines(activeSmartTrades), - [activeSmartTrades], - ); - - const [barSize, setBarSize] = useState("1h"); - const [showPriceLines, setShowPriceLines] = useState(true); - - const tradeMarkers = useMemo( - () => computeTradeMarkers(completedSmartTrades, barSize), - [completedSmartTrades, barSize], - ); - const [showTradeMarkers, setShowTradeMarkers] = useState(false); - - return ( - - } - > - - - - - - { - setBarSize(value); - }} - value={barSize} - whitelist={timeframes} - /> - - - - - - - - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/bot-details/GridDetailChart/index.ts b/apps/frontend/src/components/grid-bot/bot-details/GridDetailChart/index.ts deleted file mode 100644 index d56e3a6a..00000000 --- a/apps/frontend/src/components/grid-bot/bot-details/GridDetailChart/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./GridDetailChart"; diff --git a/apps/frontend/src/components/grid-bot/bot-details/GridDetailChart/utils/computePriceLines.ts b/apps/frontend/src/components/grid-bot/bot-details/GridDetailChart/utils/computePriceLines.ts deleted file mode 100644 index b6cf57f6..00000000 --- a/apps/frontend/src/components/grid-bot/bot-details/GridDetailChart/utils/computePriceLines.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { CreatePriceLineOptions } from "lightweight-charts"; -import type { TActiveSmartTrade } from "src/types/trpc"; -import { computePriceLine } from "src/utils/charts"; -import { getWaitingGridLinePrice } from "src/utils/grid-bot/getWaitingGridLinePrice"; - -export function computePriceLines( - smartTrades: TActiveSmartTrade[], -): CreatePriceLineOptions[] { - if (smartTrades.length === 0) { - return []; - } - - const waitingPriceLine = getWaitingGridLinePrice(smartTrades); - const otherPriceLines = smartTrades.map((smartTrade) => { - const isPositionOpen = smartTrade.entryOrder.status === "Filled"; - - if (isPositionOpen) { - return smartTrade.takeProfitOrder.price!; - } - - return smartTrade.entryOrder.price!; - }); - - const priceLines = [...otherPriceLines, waitingPriceLine].sort( - (left, right) => left - right, - ); - - return priceLines.map((priceLine) => - computePriceLine(priceLine, priceLines, waitingPriceLine), - ); -} diff --git a/apps/frontend/src/components/grid-bot/bot-details/GridDetailChart/utils/computeTradeMarkers.ts b/apps/frontend/src/components/grid-bot/bot-details/GridDetailChart/utils/computeTradeMarkers.ts deleted file mode 100644 index ac3a53db..00000000 --- a/apps/frontend/src/components/grid-bot/bot-details/GridDetailChart/utils/computeTradeMarkers.ts +++ /dev/null @@ -1,130 +0,0 @@ -import Big from "big.js"; -import type { TCompletedSmartTrade } from "src/types/trpc"; -import { computeMarker } from "src/utils/charts/marker"; -import { roundTimestamp } from "src/utils/charts/barSize"; -import type { ChartBarSize } from "../GridDetailChart"; - -type Order = { - smartTradeId: number; - orderId: number; - quantity: number; - filledPrice: number; - filledAt: number; - side: "buy" | "sell"; -}; - -type Marker = { - timestamp: number; - ordersCount: number; - averagePrice: number; - side: "buy" | "sell"; -}; - -type MarkersMap = Record; - -/** - * Creates orders buy/sell markers for `lightweight-charts` - * - * @param smartTrades - SmartTrades - * @param timeframe - Timeframe - */ -export function computeTradeMarkers( - smartTrades: TCompletedSmartTrade[], - timeframe: ChartBarSize, -) { - const orders = computeOrders(smartTrades); - - const buyMarkers = stackOrders( - orders.filter((order) => order.side === "buy"), - timeframe, - ); - const sellMarkers = stackOrders( - orders.filter((order) => order.side === "sell"), - timeframe, - ); - - const markers = [...buyMarkers, ...sellMarkers].sort( - (left, right) => left.timestamp - right.timestamp, - ); - - return markers.map((marker) => - computeMarker(marker.ordersCount, marker.timestamp, marker.side), - ); -} - -/** - * 1. Decompose buy/sell order of a SmartTrade - * 2. Merge them into a flat array - * 3. Sort by timestamp - * - * @param smartTrades - SmartTrades - */ -function computeOrders(smartTrades: TCompletedSmartTrade[]): Order[] { - if (smartTrades.length === 0) { - return []; - } - - const orders = smartTrades - .flatMap((smartTrade) => [ - smartTrade.entryOrder, - smartTrade.takeProfitOrder, - ]) - // normalize the data - .map((order) => { - if (order.filledPrice === null) { - throw new Error("computeOrders: filledPrice is null"); - } - - const normalizedOrder: Order = { - smartTradeId: order.smartTradeId, - orderId: order.id, - quantity: order.quantity, - filledPrice: order.filledPrice, - filledAt: roundTimestamp(order.filledAt.getTime(), "1m"), - side: order.side === "Buy" ? "buy" : "sell", - }; - - return normalizedOrder; - }) - // lightweight-charts: data must be asc ordered by time - .sort((left, right) => left.filledAt - right.filledAt); - - return orders; -} - -/** - * Stack multiple orders on same candlestick into one `Marker`. - * - * @param orders - Orders - * @param timeframe - Timeframe - */ -function stackOrders(orders: Order[], timeframe: ChartBarSize): Marker[] { - const markersMap = orders.reduce((acc, order) => { - const timestamp = roundTimestamp(order.filledAt, timeframe); - let marker = acc[timestamp]; - - if (marker) { - marker.ordersCount += 1; - marker.averagePrice = Number( - Big(marker.averagePrice + order.filledPrice) - .div(2) - .toNumber() - .toFixed(4), - ); - } else { - marker = { - timestamp, - ordersCount: 1, - averagePrice: order.filledPrice, - side: order.side, - }; - } - - return { - ...acc, - [timestamp]: marker, - }; - }, {}); - - return Object.values(markersMap); -} diff --git a/apps/frontend/src/components/grid-bot/bot-details/loading.tsx b/apps/frontend/src/components/grid-bot/bot-details/loading.tsx deleted file mode 100644 index 576db806..00000000 --- a/apps/frontend/src/components/grid-bot/bot-details/loading.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import Grid from "@mui/joy/Grid"; -import Skeleton from "@mui/joy/Skeleton"; -import React from "react"; - -export default function Loading() { - return ( - - - - - - - - - - ); -} diff --git a/apps/frontend/src/components/grid-bot/bot-details/page.tsx b/apps/frontend/src/components/grid-bot/bot-details/page.tsx deleted file mode 100644 index 717473b5..00000000 --- a/apps/frontend/src/components/grid-bot/bot-details/page.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import Grid from "@mui/joy/Grid"; -import Skeleton from "@mui/joy/Skeleton"; -import React, { Suspense } from "react"; -import { BotSettingsCard } from "src/components/grid-bot/bot-details/BotSettings"; -import { GridDetailChart } from "src/components/grid-bot/bot-details/GridDetailChart"; -import { ProfitsCard } from "src/components/common/smart-trades/ProfitsCard"; -import { SmartTradesTable } from "src/components/common/smart-trades/SmartTradesTable"; -import { CHART_HEIGHT } from "src/ui/charts/Chart"; - -type Props = { - botId: number; -}; - -export default function BotDetailsPage(props: Props) { - const { botId } = props; - - return ( - - - - } - > - - - - - - - } - > - - - - - - - } - > - - - - - - - } - > - - - - - ); -} diff --git a/apps/frontend/src/components/grid-bot/bots-list/BotCard/BotCard.tsx b/apps/frontend/src/components/grid-bot/bots-list/BotCard/BotCard.tsx deleted file mode 100644 index 10043f43..00000000 --- a/apps/frontend/src/components/grid-bot/bots-list/BotCard/BotCard.tsx +++ /dev/null @@ -1,166 +0,0 @@ -"use client"; - -import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward"; -import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward"; -import FormatListNumberedRtlIcon from "@mui/icons-material/FormatListNumberedRtl"; -import NumbersIcon from "@mui/icons-material/Numbers"; -import Box from "@mui/joy/Box"; -import Card from "@mui/joy/Card"; -import CardContent from "@mui/joy/CardContent"; -import Divider from "@mui/joy/Divider"; -import Link from "next/link"; -import List from "@mui/joy/List"; -import ListItem from "@mui/joy/ListItem"; -import ListItemDecorator from "@mui/joy/ListItemDecorator"; -import ListItemContent from "@mui/joy/ListItemContent"; -import Tooltip from "@mui/joy/Tooltip"; -import Typography from "@mui/joy/Typography"; -import clsx from "clsx"; -import type { FC } from "react"; -import { styled } from "@mui/joy/styles"; -import type { SxProps } from "@mui/joy/styles/types"; -import type { TGridBot } from "src/types/trpc"; -import { calcAverageQuantityPerGrid } from "src/utils/grid-bot/calcAverageQuantityPerGrid"; -import { findHighestGridLinePrice } from "src/utils/grid-bot/findHighestGridLinePrice"; -import { findLowestGridLinePrice } from "src/utils/grid-bot/findLowestGridLinePrice"; -import { toPage } from "src/utils/next/toPage"; -import { BotStatusIndicator } from "./BotStatusIndicator"; -import { Bull } from "./Bull"; - -const componentName = "BotCard"; -const classes = { - root: `${componentName}-root`, - botTitle: `${componentName}-bot-title`, -}; - -const Root = styled(Card)(() => ({ - /* Styles applied to the root element. */ - [`& .${classes.root}`]: {}, - [`& .${classes.botTitle}`]: { - color: "inherit", - textDecoration: "none", - - "&:hover": { - cursor: "pointer", - textDecoration: "underline", - }, - }, -})); - -export type BotCardProps = { - className?: string; - bot: TGridBot; - sx?: SxProps; -}; - -export const BotCard: FC = (props) => { - const { bot, sx, className } = props; - - // @todo - // const initialInvestmentInQuote = calcInitialInvestmentInQuote( - // bot.initialInvestment - // ); - const initialInvestmentInQuote = "hz"; // @todo - const averageQuantityPerGrid = calcAverageQuantityPerGrid( - bot.settings.gridLines, - ); - const gridLevels = bot.settings.gridLines.length; - - const lowPrice = findLowestGridLinePrice(bot.settings.gridLines); - const highPrice = findHighestGridLinePrice(bot.settings.gridLines); - - return ( - - - - - - {bot.name} - - - - - - - - {bot.baseCurrency}/{bot.quoteCurrency} {" "} - - - {initialInvestmentInQuote} {bot.quoteCurrency} - - - - - - - - - - - - - - - - High price - - {`${highPrice} ${bot.quoteCurrency}`} - - - - - - - - - - Low price - - {`${lowPrice} ${bot.quoteCurrency}`} - - - - - - - - - - - - Avg. Qty. per grid - - {`${averageQuantityPerGrid.toFixed(4)} ${bot.baseCurrency}`} - - - - - - - - - - - Grid levels - - {gridLevels} - - - - - - - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/bots-list/BotCard/BotStatusIndicator.tsx b/apps/frontend/src/components/grid-bot/bots-list/BotCard/BotStatusIndicator.tsx deleted file mode 100644 index 5e2e0f78..00000000 --- a/apps/frontend/src/components/grid-bot/bots-list/BotCard/BotStatusIndicator.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import FiberManualRecordIcon from "@mui/icons-material/FiberManualRecord"; -import type { SxProps } from "@mui/joy/styles/types"; -import type { FC } from "react"; -import React from "react"; -import clsx from "clsx"; -import Chip from "@mui/joy/Chip"; -import { styled } from "@mui/joy/styles"; -import type { TGridBot } from "src/types/trpc"; - -const componentName = "BotStatusIndicator"; -const classes = { - root: `${componentName}-root`, -}; -const StyledChip = styled(Chip)(() => ({ - /* Styles applied to the root element. */ - [`&.${classes.root}`]: {}, -})); - -type BotStatusIndicatorProps = { - className?: string; - bot: TGridBot; - sx?: SxProps; -}; - -export const BotStatusIndicator: FC = (props) => { - const { className, bot, sx } = props; - - if (bot.enabled) { - return ( - } - sx={sx} - variant="soft" - > - Running - - ); - } - - return ( - } - sx={sx} - variant="soft" - > - Disabled - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/bots-list/BotCard/Bull.tsx b/apps/frontend/src/components/grid-bot/bots-list/BotCard/Bull.tsx deleted file mode 100644 index 69c5785d..00000000 --- a/apps/frontend/src/components/grid-bot/bots-list/BotCard/Bull.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import type { FC } from "react"; -import Box from "@mui/joy/Box"; - -export const Bull: FC = () => { - return ( - - • - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/bots-list/BotCard/index.ts b/apps/frontend/src/components/grid-bot/bots-list/BotCard/index.ts deleted file mode 100644 index ea6d693c..00000000 --- a/apps/frontend/src/components/grid-bot/bots-list/BotCard/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./BotCard"; diff --git a/apps/frontend/src/components/grid-bot/bots-list/BotList.tsx b/apps/frontend/src/components/grid-bot/bots-list/BotList.tsx deleted file mode 100644 index 0e76d6e1..00000000 --- a/apps/frontend/src/components/grid-bot/bots-list/BotList.tsx +++ /dev/null @@ -1,21 +0,0 @@ -"use client"; - -import Grid from "@mui/joy/Grid"; -import type { FC } from "react"; -import React from "react"; -import { BotCard } from "src/components/grid-bot/bots-list/BotCard"; -import { tClient } from "src/lib/trpc/client"; - -export const BotList: FC = () => { - const [bots] = tClient.gridBot.list.useSuspenseQuery(); - - return ( - - {bots.map((bot) => ( - - - - ))} - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/bots-list/BotListSkeleton.tsx b/apps/frontend/src/components/grid-bot/bots-list/BotListSkeleton.tsx deleted file mode 100644 index 0eabe8cf..00000000 --- a/apps/frontend/src/components/grid-bot/bots-list/BotListSkeleton.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import Grid from "@mui/joy/Grid"; -import Skeleton from "@mui/joy/Skeleton"; -import type { FC } from "react"; -import React from "react"; - -const BOTS_LENGTH = 8; - -export const BotListSkeleton: FC = () => { - const bots = Array.from({ length: BOTS_LENGTH }); - - return ( - - {bots.map((_, i) => ( - - - - ))} - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/bots-list/loading.tsx b/apps/frontend/src/components/grid-bot/bots-list/loading.tsx deleted file mode 100644 index 3cabd4a5..00000000 --- a/apps/frontend/src/components/grid-bot/bots-list/loading.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from "react"; -import Button from "@mui/joy/Button"; -import Grid from "@mui/joy/Grid"; -import NextLink from "next/link"; -import { toPage } from "src/utils/next/toPage"; -import { BotListSkeleton } from "./BotListSkeleton"; - -export default function Loading() { - return ( - - - - - - - - - - ); -} diff --git a/apps/frontend/src/components/grid-bot/bots-list/page.tsx b/apps/frontend/src/components/grid-bot/bots-list/page.tsx deleted file mode 100644 index ccb21cf0..00000000 --- a/apps/frontend/src/components/grid-bot/bots-list/page.tsx +++ /dev/null @@ -1,27 +0,0 @@ -"use client"; - -import NextLink from "next/link"; -import Button from "@mui/joy/Button"; -import Grid from "@mui/joy/Grid"; -import React, { Suspense } from "react"; -import { BotList } from "src/components/grid-bot/bots-list/BotList"; -import { BotListSkeleton } from "src/components/grid-bot/bots-list/BotListSkeleton"; -import { toPage } from "src/utils/next/toPage"; - -export default function BotPage() { - return ( - - - - - - - }> - - - - - ); -} diff --git a/apps/frontend/src/components/grid-bot/create-bot/GridChart/GridChart.tsx b/apps/frontend/src/components/grid-bot/create-bot/GridChart/GridChart.tsx deleted file mode 100644 index 0c53ac78..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/GridChart/GridChart.tsx +++ /dev/null @@ -1,91 +0,0 @@ -"use client"; - -import Box from "@mui/joy/Box"; -import Skeleton from "@mui/joy/Skeleton"; -import type { IGridLine } from "@opentrader/types"; -import type { FC } from "react"; -import React, { Suspense, useDeferredValue, useMemo, useState } from "react"; -import type { GridBotFormChartBarSize } from "src/store/bot-form"; -import { TIMEFRAMES } from "src/store/bot-form/constants"; -import { Chart, ChartOptions } from "src/ui/charts/Chart"; -import { CHART_HEIGHT } from "src/ui/charts/Chart/constants"; -import { ExchangeAccountField } from "src/components/grid-bot/create-bot/form/fields/ExchangeAccountField"; -import { PairField } from "src/components/grid-bot/create-bot/form/fields/PairField"; -import { FlexSpacer } from "src/ui/FlexSpacer"; -import { BarSizeSelect } from "src/ui/selects/BarSizeSelect"; -import { InputSkeleton } from "src/ui/InputSkeleton"; -import { computePriceLines } from "./utils"; - -type GridChartProps = { - symbolId: string; - barSize: GridBotFormChartBarSize; - onBarSizeChange?: (value: GridBotFormChartBarSize) => void; - gridLines: IGridLine[]; - currentAssetPrice: number; -}; - -export const GridChart: FC = ({ - symbolId, - barSize, - onBarSizeChange, - gridLines, - currentAssetPrice, -}) => { - const deferredSymbolId = useDeferredValue(symbolId); - const isStale = symbolId !== deferredSymbolId; - - const priceLines = useMemo( - () => computePriceLines(gridLines, currentAssetPrice), - [gridLines, currentAssetPrice], - ); - const [showPriceLines, setShowPriceLines] = useState(true); - - return ( - - } - > - - }> - - - - }> - - - - { - if (onBarSizeChange) { - onBarSizeChange(value); - } - }} - value={barSize} - whitelist={TIMEFRAMES} - /> - - - - - - - - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/GridChart/index.ts b/apps/frontend/src/components/grid-bot/create-bot/GridChart/index.ts deleted file mode 100644 index f9855c40..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/GridChart/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./GridChart"; diff --git a/apps/frontend/src/components/grid-bot/create-bot/GridChart/utils.ts b/apps/frontend/src/components/grid-bot/create-bot/GridChart/utils.ts deleted file mode 100644 index 29da361c..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/GridChart/utils.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { IGridLine } from "@opentrader/types"; -import type { CreatePriceLineOptions } from "lightweight-charts"; -import { computePriceLine } from "src/utils/charts"; -import { waitingPriceFromCurrentAssetPrice } from "src/utils/grid-bot/waitingPriceFromCurrentAssetPrice"; - -export function computePriceLines( - gridLines: IGridLine[], - currentAssetPrice: number, -): CreatePriceLineOptions[] { - const prices = gridLines.map((gridLine) => gridLine.price); - const waitingPrice = waitingPriceFromCurrentAssetPrice( - prices, - currentAssetPrice, - ); - - return prices.map((price) => computePriceLine(price, prices, waitingPrice)); -} diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/AdvancedGridForm.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/AdvancedGridForm.tsx deleted file mode 100644 index e216eca7..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/AdvancedGridForm.tsx +++ /dev/null @@ -1,40 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React from "react"; -import Grid from "@mui/joy/Grid"; -import Button from "@mui/joy/Button"; -import { addGridLine } from "src/store/bot-form"; -import { selectGridLines } from "src/store/bot-form/selectors"; -import { useAppDispatch, useAppSelector } from "src/store/hooks"; -import { AdvancedGridFormItem } from "./AdvancedGridFormItem"; - -export const AdvancedGridForm: FC = () => { - const dispatch = useAppDispatch(); - const gridLines = useAppSelector(selectGridLines); - - const handleAddGridLine = () => { - dispatch( - addGridLine({ - price: 1, // @todo calc from store - quantity: 1, // @todo calc from store - }), - ); - }; - - const inverseIndex = (index: number) => gridLines.length - 1 - index; - - return ( - - - {gridLines.map((gridLine, i) => ( - - ))} - - - - - - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/AdvancedGridFormItem.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/AdvancedGridFormItem.tsx deleted file mode 100644 index 74dba3fa..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/AdvancedGridFormItem.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import Grid from "@mui/joy/Grid"; -import Skeleton from "@mui/joy/Skeleton"; -import type { FC } from "react"; -import React, { Suspense } from "react"; -import { selectGridLines } from "src/store/bot-form/selectors"; -import { useAppSelector } from "src/store/hooks"; -import { RemoveGridLineButton } from "./RemoveGridLineButton"; -import { GridLinePriceField } from "./fields/GridLinePriceField"; -import { GridLineQuantityField } from "./fields/GridLineQuantityField"; - -type AdvancedGridFormItemProps = { - gridLineIndex: number; -}; - -export const AdvancedGridFormItem: FC = (props) => { - const { gridLineIndex } = props; - - const gridLines = useAppSelector(selectGridLines); - - // The last gridLine is just a SELL order, - // so the quantity is specified in the prev gridLine. - const isDisabled = gridLineIndex === gridLines.length - 1; - - return ( - - - } - > - - - - - - } - > - - - - - - - - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/RemoveGridLineButton.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/RemoveGridLineButton.tsx deleted file mode 100644 index e68f420e..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/RemoveGridLineButton.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import Button from "@mui/joy/Button"; -import type { FC } from "react"; -import React from "react"; -import { removeGridLine } from "src/store/bot-form"; -import { useAppDispatch } from "src/store/hooks"; - -type RemoveGridLineButtonProps = { - gridLineIndex: number; - className?: string; -}; - -export const RemoveGridLineButton: FC = (props) => { - const { className, gridLineIndex } = props; - - const dispatch = useAppDispatch(); - - const handleRemove = () => { - dispatch(removeGridLine(gridLineIndex)); - }; - - return ( - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/fields/GridLinePriceField.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/fields/GridLinePriceField.tsx deleted file mode 100644 index d8064bd7..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/fields/GridLinePriceField.tsx +++ /dev/null @@ -1,61 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React, { useEffect, useState } from "react"; -import { PriceInput } from "src/ui/inputs/PriceInput"; -import { tClient } from "src/lib/trpc/client"; -import { updateGridLinePrice } from "src/store/bot-form"; -import { selectGridLine, selectSymbolId } from "src/store/bot-form/selectors"; -import { useAppDispatch, useAppSelector } from "src/store/hooks"; - -type GridLinePriceFieldProps = { - gridLineIndex: number; - className?: string; -}; - -export const GridLinePriceField: FC = (props) => { - const { className, gridLineIndex } = props; - - const dispatch = useAppDispatch(); - - const { price: reduxValue } = useAppSelector(selectGridLine(gridLineIndex)); - const [value, setValue] = useState(String(reduxValue)); - useEffect(() => { - setValue(`${reduxValue}`); - }, [reduxValue]); - - const symbolId = useAppSelector(selectSymbolId); - const [symbol] = tClient.symbol.getOne.useSuspenseQuery({ - symbolId, - }); - - const handleChange = (e: React.ChangeEvent) => { - setValue(e.target.value); - }; - - const handleBlur = () => { - if (value.length > 0) { - dispatch( - updateGridLinePrice({ - gridLineIndex, - price: Number(value), - }), - ); - } else { - setValue(String(reduxValue)); - } - }; - - return ( - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/fields/GridLineQuantityField.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/fields/GridLineQuantityField.tsx deleted file mode 100644 index 1ff215c7..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/fields/GridLineQuantityField.tsx +++ /dev/null @@ -1,67 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React, { useEffect, useState } from "react"; -import { QuantityInput } from "src/ui/inputs/QuantityInput"; -import { tClient } from "src/lib/trpc/client"; -import { updateGridLineQuantity } from "src/store/bot-form"; -import { selectGridLine, selectSymbolId } from "src/store/bot-form/selectors"; -import { useAppDispatch, useAppSelector } from "src/store/hooks"; - -type GridLineQuantityFieldProps = { - gridLineIndex: number; - disabled?: boolean; - className?: string; -}; - -export const GridLineQuantityField: FC = ( - props, -) => { - const { className, gridLineIndex, disabled } = props; - - const dispatch = useAppDispatch(); - - const symbolId = useAppSelector(selectSymbolId); - const [symbol] = tClient.symbol.getOne.useSuspenseQuery({ - symbolId, - }); - - const { quantity: reduxValue } = useAppSelector( - selectGridLine(gridLineIndex), - ); - const [value, setValue] = useState(`${reduxValue}`); - useEffect(() => { - setValue(`${reduxValue}`); - }, [reduxValue]); - - const handleChange = (e: React.ChangeEvent) => { - setValue(e.target.value); - }; - - const handleBlur = () => { - if (!isNaN(Number(value))) { - dispatch( - updateGridLineQuantity({ - gridLineIndex, - quantity: Number(value), - }), - ); - } else { - setValue(`${reduxValue}`); - } - }; - - return ( - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/index.ts b/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/index.ts deleted file mode 100644 index 28e22017..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/AdvancedGridForm/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./AdvancedGridForm"; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/CreateGridForm.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/CreateGridForm.tsx deleted file mode 100644 index 8f63a756..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/CreateGridForm.tsx +++ /dev/null @@ -1,136 +0,0 @@ -"use client"; - -import Box from "@mui/joy/Box"; -import Divider from "@mui/joy/Divider"; -import Skeleton from "@mui/joy/Skeleton"; -import { calcGridLinesWithPriceFilter } from "@opentrader/tools"; -import type { FC } from "react"; -import React, { Suspense } from "react"; -import Grid from "@mui/joy/Grid"; -import Card from "@mui/joy/Card"; -import { InputSkeleton } from "src/ui/InputSkeleton"; -import { useIsStale } from "src/hooks/useIsStale"; -import { tClient } from "src/lib/trpc/client"; -import { - setHighPrice, - setLowPrice, - setQuantityPerGrid, - updateGridLines, -} from "src/store/bot-form"; -import { - selectGridLinesNumber, - selectHighPrice, - selectLowPrice, - selectQuantityPerGrid, - selectSymbolId, -} from "src/store/bot-form/selectors"; -import { useAppDispatch, useAppSelector } from "src/store/hooks"; -import { SubmitButton } from "./SubmitButton"; -import { FormTypeTabs } from "./FormTypeTabs"; -import { BotNameField } from "./fields/BotNameField"; -import { AdvancedGridForm } from "./AdvancedGridForm"; -import { InvestmentField } from "./fields/InvestmentField"; -import { SimpleGridForm } from "./SimpleGridForm"; - -export const CreateGridBotForm: FC = () => { - const dispatch = useAppDispatch(); - - // Update `quantityPerGrid` when symbol change - const symbolId = useAppSelector(selectSymbolId); - const { data: symbol } = tClient.symbol.getOne.useQuery( - { symbolId }, - { - refetchOnWindowFocus: false, - }, - ); - if (useIsStale(symbol)) { - if (symbol) { - const quantityPerGrid = - symbol.filters.limits.amount?.min?.toString() || ""; - dispatch(setQuantityPerGrid(quantityPerGrid)); - } - } - - // Update high/low prices when symbol change - const { data: options } = tClient.gridBot.formOptions.useQuery( - { symbolId }, - { - refetchOnWindowFocus: false, - }, - ); - if (useIsStale(options)) { - if (options) { - dispatch(setHighPrice(options.highPrice)); - dispatch(setLowPrice(options.lowPrice)); - } - } - - // Recalculate grid lines - const highPrice = useAppSelector(selectHighPrice); - const lowPrice = useAppSelector(selectLowPrice); - const gridLinesNumber = useAppSelector(selectGridLinesNumber); - const quantityPerGrid = useAppSelector(selectQuantityPerGrid); - - const isStale = [ - useIsStale(highPrice), - useIsStale(lowPrice), - useIsStale(gridLinesNumber), - useIsStale(quantityPerGrid), - useIsStale(symbol), - ].includes(true); - - if (isStale) { - if (symbol) { - const gridLines = calcGridLinesWithPriceFilter( - highPrice, - lowPrice, - gridLinesNumber, - Number(quantityPerGrid), - symbol.filters, - ); - - dispatch(updateGridLines(gridLines)); - } - } - - return ( - - - } - > - - - } - simpleForm={} - /> - - - - - - - }> - - - - - - - - - - - - - - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/FormTypeTabs.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/FormTypeTabs.tsx deleted file mode 100644 index 9c853c46..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/FormTypeTabs.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import Tab, { tabClasses } from "@mui/joy/Tab"; -import TabList from "@mui/joy/TabList"; -import Tabs from "@mui/joy/Tabs"; -import TabPanel from "@mui/joy/TabPanel"; -import type { FC, ReactNode } from "react"; -import React from "react"; -import type { GridBotFormType } from "src/store/bot-form"; -import { changeFormType } from "src/store/bot-form"; -import { selectFormType } from "src/store/bot-form/selectors"; -import { useAppDispatch, useAppSelector } from "src/store/hooks"; - -const FormTypes: Record = { - simple: "simple", - advanced: "advanced", -}; - -type FormTypeTabsProps = { - simpleForm: ReactNode; - advancedForm: ReactNode; -}; - -export const FormTypeTabs: FC = ({ - simpleForm, - advancedForm, -}) => { - const formType = useAppSelector(selectFormType); - const dispatch = useAppDispatch(); - - const handleChange = ( - event: React.SyntheticEvent | null, - newValue: GridBotFormType | null, - ) => { - // disallow un-toggling current button - if (newValue === null) return; - - dispatch(changeFormType(newValue)); - }; - - return ( - { - handleChange(event, newValue as GridBotFormType); - }} - sx={{ - borderRadius: "md", - overflow: "auto", - boxShadow: "sm", - }} - value={formType} - > - - - Easy form - - - Advanced form - - - - {simpleForm} - {advancedForm} - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/SimpleGridForm.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/SimpleGridForm.tsx deleted file mode 100644 index e0b61b32..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/SimpleGridForm.tsx +++ /dev/null @@ -1,38 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React, { Suspense } from "react"; -import Grid from "@mui/joy/Grid"; -import { InputSkeleton } from "src/ui/InputSkeleton"; -import { QuantityPerGridField } from "./fields/QuantityPerGridField"; -import { GridLevelsField } from "./fields/GridLevelsField"; -import { HighPriceField } from "./fields/HighPriceField"; -import { LowPriceField } from "./fields/LowPriceField"; - -export const SimpleGridForm: FC = () => { - return ( - - - }> - - - - - - }> - - - - - - }> - - - - - - - - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/fields/GridLevelsField.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/fields/GridLevelsField.tsx deleted file mode 100644 index aafd8449..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/fields/GridLevelsField.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import type { FC } from "react"; -import React, { useState } from "react"; -import FormControl from "@mui/joy/FormControl"; -import FormLabel from "@mui/joy/FormLabel"; -import Input from "@mui/joy/Input"; -import { changeGridLinesNumber } from "src/store/bot-form"; -import { selectGridLinesNumber } from "src/store/bot-form/selectors"; -import { useAppDispatch, useAppSelector } from "src/store/hooks"; - -type GridLevelsFieldProps = { - disabled?: boolean; - readOnly?: boolean; -}; - -const fieldName = "gridLevels" as const; - -export const GridLevelsField: FC = (props) => { - const { disabled, readOnly } = props; - const dispatch = useAppDispatch(); - - const reduxValue = useAppSelector(selectGridLinesNumber); - const [value, setValue] = useState(reduxValue); - - const handleChange = (e: React.ChangeEvent) => { - setValue(e.target.valueAsNumber); - }; - - const handleBlur = () => { - if (Number.isInteger(value)) { - dispatch(changeGridLinesNumber(value)); - } else { - setValue(reduxValue); - } - }; - - return ( - - Grid levels - - - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/fields/HighPriceField.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/fields/HighPriceField.tsx deleted file mode 100644 index 7542a27d..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/fields/HighPriceField.tsx +++ /dev/null @@ -1,55 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React, { useEffect, useState } from "react"; -import { PriceInput } from "src/ui/inputs/PriceInput"; -import { tClient } from "src/lib/trpc/client"; -import { changeHighPrice } from "src/store/bot-form"; -import { selectHighPrice, selectSymbolId } from "src/store/bot-form/selectors"; -import { useAppDispatch, useAppSelector } from "src/store/hooks"; - -type HighPriceFieldProps = { - disabled?: boolean; - readOnly?: boolean; -}; - -export const HighPriceField: FC = (props) => { - const { disabled, readOnly } = props; - - const symbolId = useAppSelector(selectSymbolId); - const [symbol] = tClient.symbol.getOne.useSuspenseQuery({ symbolId }); - - const dispatch = useAppDispatch(); - - const reduxValue = useAppSelector(selectHighPrice); - const [value, setValue] = useState(`${reduxValue}`); - - useEffect(() => { - setValue(`${reduxValue}`); - }, [reduxValue]); - - const handleChange = (e: React.ChangeEvent) => { - setValue(e.target.value); - }; - - const handleBlur = () => { - if (value.length > 0) { - dispatch(changeHighPrice(Number(value))); - } else { - setValue(`${reduxValue}`); - } - }; - - return ( - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/fields/LowPriceField.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/fields/LowPriceField.tsx deleted file mode 100644 index 67f840c3..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/fields/LowPriceField.tsx +++ /dev/null @@ -1,54 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React, { useEffect, useState } from "react"; -import { PriceInput } from "src/ui/inputs/PriceInput"; -import { tClient } from "src/lib/trpc/client"; -import { changeLowPrice } from "src/store/bot-form"; -import { selectLowPrice, selectSymbolId } from "src/store/bot-form/selectors"; -import { useAppDispatch, useAppSelector } from "src/store/hooks"; - -type LowPriceFieldProps = { - disabled?: boolean; - readOnly?: boolean; -}; - -export const LowPriceField: FC = (props) => { - const { disabled, readOnly } = props; - const symbolId = useAppSelector(selectSymbolId); - const [symbol] = tClient.symbol.getOne.useSuspenseQuery({ symbolId }); - - const dispatch = useAppDispatch(); - - const reduxValue = useAppSelector(selectLowPrice); - const [value, setValue] = useState(`${reduxValue}`); - - useEffect(() => { - setValue(`${reduxValue}`); - }, [reduxValue]); - - const handleChange = (e: React.ChangeEvent) => { - setValue(e.target.value); - }; - - const handleBlur = () => { - if (value.length > 0) { - dispatch(changeLowPrice(Number(value))); - } else { - setValue(`${reduxValue}`); - } - }; - - return ( - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/fields/QuantityPerGridField.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/fields/QuantityPerGridField.tsx deleted file mode 100644 index 7aa500bb..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/fields/QuantityPerGridField.tsx +++ /dev/null @@ -1,58 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React, { useEffect, useState } from "react"; -import { tClient } from "src/lib/trpc/client"; -import { changeQuantityPerGrid } from "src/store/bot-form"; -import { - selectQuantityPerGrid, - selectSymbolId, -} from "src/store/bot-form/selectors"; -import { useAppDispatch, useAppSelector } from "src/store/hooks"; -import { QuantityInput } from "src/ui/inputs/QuantityInput"; - -type QuantityPerGridFieldProps = { - disabled?: boolean; - readOnly?: boolean; -}; - -export const QuantityPerGridField: FC = (props) => { - const { disabled, readOnly } = props; - const symbolId = useAppSelector(selectSymbolId); - const [symbol] = tClient.symbol.getOne.useSuspenseQuery({ symbolId }); - - const dispatch = useAppDispatch(); - - const reduxValue = useAppSelector(selectQuantityPerGrid); - const [value, setValue] = useState(reduxValue); - - useEffect(() => { - setValue(reduxValue); - }, [reduxValue]); - - const handleChange = (e: React.ChangeEvent) => { - setValue(e.target.value); - }; - - const handleBlur = () => { - if (!isNaN(Number(value))) { - dispatch(changeQuantityPerGrid(value)); - } else { - setValue(`${reduxValue}`); - } - }; - - return ( - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/index.ts b/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/index.ts deleted file mode 100644 index d7b18144..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/SimpleGridForm/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./SimpleGridForm"; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/SubmitButton.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/SubmitButton.tsx deleted file mode 100644 index f59599f9..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/SubmitButton.tsx +++ /dev/null @@ -1,49 +0,0 @@ -"use client"; - -import CircularProgress from "@mui/joy/CircularProgress"; -import Button from "@mui/joy/Button"; -import { useRouter } from "next/navigation"; -import type { FC } from "react"; -import React from "react"; -import { tClient } from "src/lib/trpc/client"; -import { selectBotFormState } from "src/store/bot-form/selectors"; -import { useAppSelector } from "src/store/hooks"; -import { useSnackbar } from "src/ui/snackbar"; -import { toPage } from "src/utils/next/toPage"; -import { mapFormToDto } from "./helpers/mapFormToDto"; - -export const SubmitButton: FC = () => { - const { showSnackbar } = useSnackbar(); - const router = useRouter(); - - const botFormState = useAppSelector(selectBotFormState); - - const { mutate, isLoading } = tClient.gridBot.create.useMutation({ - onSuccess(bot) { - showSnackbar("Bot created successfully"); - - setTimeout(() => { - router.push(toPage("grid-bot/:id", bot.id)); - }, 1000); - }, - }); - - const handleSubmit = () => { - const dto = mapFormToDto(botFormState); - - mutate(dto); - }; - - return ( - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/fields/BotNameField.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/fields/BotNameField.tsx deleted file mode 100644 index b2253b6b..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/fields/BotNameField.tsx +++ /dev/null @@ -1,61 +0,0 @@ -"use client"; - -import FormControl from "@mui/joy/FormControl"; -import FormHelperText from "@mui/joy/FormHelperText"; -import FormLabel from "@mui/joy/FormLabel"; -import IconButton from "@mui/joy/IconButton"; -import Input from "@mui/joy/Input"; -import type { FC } from "react"; -import React, { useEffect, useState } from "react"; -import ReplayIcon from "@mui/icons-material/Replay"; -import { changeBotName } from "src/store/bot-form"; -import { selectBotName } from "src/store/bot-form/selectors"; -import { useAppDispatch, useAppSelector } from "src/store/hooks"; -import { generateBotName } from "src/utils/bot-name-generator"; - -export const BotNameField: FC = () => { - const dispatch = useAppDispatch(); - - const reduxValue = useAppSelector(selectBotName); - const [value, setValue] = useState(reduxValue); - useEffect(() => { - setValue(`${reduxValue}`); - }, [reduxValue]); - - const handleChange = (e: React.ChangeEvent) => { - setValue(e.target.value); - }; - - const handleBlur = () => { - if (value.length > 0) { - dispatch(changeBotName(value)); - } else { - setValue(reduxValue); - } - }; - - const regenerateBotName = () => { - dispatch(changeBotName(generateBotName())); - }; - - const errorMessage = value.length === 0 ? "Must be defined" : null; - - return ( - - Bot name - - - - - } - onBlur={handleBlur} - onChange={handleChange} - value={value} - /> - - {errorMessage ? {errorMessage} : null} - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/fields/ExchangeAccountField.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/fields/ExchangeAccountField.tsx deleted file mode 100644 index c6c4ec55..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/fields/ExchangeAccountField.tsx +++ /dev/null @@ -1,38 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React from "react"; -import { ExchangeAccountSelect } from "src/ui/selects/ExchangeAccountSelect"; -import { tClient } from "src/lib/trpc/client"; -import { setExchangeAccountId, setExchangeCode } from "src/store/bot-form"; -import { selectExchangeAccountId } from "src/store/bot-form/selectors"; -import { useAppDispatch, useAppSelector } from "src/store/hooks"; -import type { TExchangeAccount } from "src/types/trpc"; - -export const ExchangeAccountField: FC = () => { - const dispatch = useAppDispatch(); - const [exchangeAccounts] = tClient.exchangeAccount.list.useSuspenseQuery(); - - const id = useAppSelector(selectExchangeAccountId); - const handleIdChange = (exchange: TExchangeAccount | null) => { - if (exchange === null) { - throw new Error( - "ExchangeAccountField: Cannot reset exchange account input", - ); - } - - dispatch(setExchangeAccountId(exchange.id)); - dispatch(setExchangeCode(exchange.exchangeCode)); - }; - - const selectedExchange = exchangeAccounts.find( - (exchange) => exchange.id === id, - ); - - return ( - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/fields/FormTypeField.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/fields/FormTypeField.tsx deleted file mode 100644 index abdd8d4a..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/fields/FormTypeField.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import Tabs from "@mui/joy/Tabs"; -import TabList from "@mui/joy/TabList"; -import Tab from "@mui/joy/Tab"; -import type { FC } from "react"; -import React from "react"; -import type { GridBotFormType } from "src/store/bot-form"; -import { changeFormType } from "src/store/bot-form"; -import { selectFormType } from "src/store/bot-form/selectors"; -import { useAppDispatch, useAppSelector } from "src/store/hooks"; - -export const FormTypeField: FC = () => { - const formType = useAppSelector(selectFormType); - const dispatch = useAppDispatch(); - - const handleChange = ( - event: React.SyntheticEvent | null, - newValue: GridBotFormType | null, - ) => { - // disallow un-toggling current button - if (newValue === null) return; - - dispatch(changeFormType(newValue)); - }; - - return ( - { - handleChange(event, newValue as GridBotFormType); - }} - sx={{ - mt: -2, - mx: -2, - borderRadius: "md", - overflow: "auto", - }} - value={formType} - > - - - Easy form - - - Advanced form - - - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/fields/InvestmentField/InvestmentField.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/fields/InvestmentField/InvestmentField.tsx deleted file mode 100644 index 7282049b..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/fields/InvestmentField/InvestmentField.tsx +++ /dev/null @@ -1,58 +0,0 @@ -"use client"; - -import type { FC } from "react"; -import React from "react"; -import { computeInvestmentAmount, decomposeSymbolId } from "@opentrader/tools"; -import FormControl from "@mui/joy/FormControl"; -import FormLabel from "@mui/joy/FormLabel"; -import Input from "@mui/joy/Input"; -import { tClient } from "src/lib/trpc/client"; -import { selectGridLines, selectSymbolId } from "src/store/bot-form/selectors"; -import { useAppSelector } from "src/store/hooks"; -import { InvestmentFieldHelperText } from "./InvestmentFieldHelperText"; - -type InvestmentFieldProps = { - className?: string; -}; - -export const InvestmentField: FC = (props) => { - const { className } = props; - - const symbolId = useAppSelector(selectSymbolId); - const { quoteCurrency } = decomposeSymbolId(symbolId); - - const [currentAssetPrice] = tClient.symbol.price.useSuspenseQuery({ - symbolId, - }); - const [symbol] = tClient.symbol.getOne.useSuspenseQuery({ - symbolId, - }); - - const gridLines = useAppSelector(selectGridLines); - - const { baseCurrencyAmount, quoteCurrencyAmount, totalInQuoteCurrency } = - computeInvestmentAmount(symbol, gridLines, currentAssetPrice.price); - - const inputId = "investment-field"; - const label = "Investment"; - - return ( - - {label} - - {quoteCurrency}} - id={inputId} - type="number" - value={totalInQuoteCurrency} - /> - - - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/fields/InvestmentField/InvestmentFieldHelperText.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/fields/InvestmentField/InvestmentFieldHelperText.tsx deleted file mode 100644 index 5644e975..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/fields/InvestmentField/InvestmentFieldHelperText.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { decomposeSymbolId } from "@opentrader/tools"; -import FormHelperText from "@mui/joy/FormHelperText"; -import type { FC } from "react"; -import { selectSymbolId } from "src/store/bot-form/selectors"; -import { useAppSelector } from "src/store/hooks"; - -type InvestmentFieldHelperTextProps = { - baseCurrencyAmount: string; // numeric string - quoteCurrencyAmount: string; // numeric string - totalInQuoteCurrency: string; // numeric string -}; - -export const InvestmentFieldHelperText: FC = ({ - baseCurrencyAmount, - quoteCurrencyAmount, - totalInQuoteCurrency, -}) => { - const symbolId = useAppSelector(selectSymbolId); - const { baseCurrency, quoteCurrency } = decomposeSymbolId(symbolId); - - return ( - - - {baseCurrencyAmount} {baseCurrency} - - + - - {quoteCurrencyAmount} {quoteCurrency} - - - - {totalInQuoteCurrency} {quoteCurrency} - - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/fields/InvestmentField/index.ts b/apps/frontend/src/components/grid-bot/create-bot/form/fields/InvestmentField/index.ts deleted file mode 100644 index 88495f65..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/fields/InvestmentField/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./InvestmentField"; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/fields/PairField.tsx b/apps/frontend/src/components/grid-bot/create-bot/form/fields/PairField.tsx deleted file mode 100644 index 4dde2944..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/fields/PairField.tsx +++ /dev/null @@ -1,38 +0,0 @@ -"use client"; - -import type { ISymbolInfo } from "@opentrader/types"; -import type { FC } from "react"; -import React from "react"; -import { SymbolSelect } from "src/ui/selects/SymbolSelect"; -import { tClient } from "src/lib/trpc/client"; -import { changeSymbolId } from "src/store/bot-form"; -import { - selectExchangeCode, - selectSymbolId, -} from "src/store/bot-form/selectors"; -import { useAppDispatch, useAppSelector } from "src/store/hooks"; - -export const PairField: FC = () => { - const dispatch = useAppDispatch(); - const exchangeCode = useAppSelector(selectExchangeCode); - const [symbols] = tClient.symbol.list.useSuspenseQuery(exchangeCode); - - const symbolId = useAppSelector(selectSymbolId); - const handleSymbolIdChange = (symbol: ISymbolInfo | null) => { - if (symbol === null) { - throw new Error("PairField: Cannot reset symbol input"); - } - - dispatch(changeSymbolId(symbol.symbolId)); - }; - - const symbol = symbols.find((symbol) => symbol.symbolId === symbolId); - - return ( - - ); -}; diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/helpers/mapFormToDto.ts b/apps/frontend/src/components/grid-bot/create-bot/form/helpers/mapFormToDto.ts deleted file mode 100644 index 140d367e..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/helpers/mapFormToDto.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { decomposeSymbolId } from "@opentrader/tools"; -import type { GridBotFormState } from "src/store/bot-form"; -import type { TGridBotCreateInput } from "src/types/trpc"; - -export function mapFormToDto(state: GridBotFormState): TGridBotCreateInput { - const { gridLines, symbolId, exchangeAccountId, botName } = state; - - const { baseCurrency, quoteCurrency } = decomposeSymbolId(symbolId); - - return { - exchangeAccountId, - data: { - name: botName, - settings: { - gridLines, - }, - baseCurrency, - quoteCurrency, - }, - }; -} diff --git a/apps/frontend/src/components/grid-bot/create-bot/form/index.ts b/apps/frontend/src/components/grid-bot/create-bot/form/index.ts deleted file mode 100644 index 8fed3934..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/form/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./CreateGridForm"; diff --git a/apps/frontend/src/components/grid-bot/create-bot/hooks/usePagaData.ts b/apps/frontend/src/components/grid-bot/create-bot/hooks/usePagaData.ts deleted file mode 100644 index dc10f8a4..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/hooks/usePagaData.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { tClient } from "src/lib/trpc/client"; - -export function usePageData() { - const [exchangeAccounts] = tClient.exchangeAccount.list.useSuspenseQuery(); - const exchangeAccount = exchangeAccounts[0]; - - const [symbols] = tClient.symbol.list.useSuspenseQuery( - exchangeAccount.exchangeCode, - ); - - // assume that every exchange has a BTC/USDT pair - // if not, then get the first one - const symbol = - symbols.find((symbol) => symbol.currencyPair === "BTC/USDT") || symbols[0]; - - const [{ price: currentAssetPrice }] = tClient.symbol.price.useSuspenseQuery({ - symbolId: symbol.symbolId, - }); - - const [{ lowPrice, highPrice }] = - tClient.gridBot.formOptions.useSuspenseQuery({ - symbolId: symbol.symbolId, - }); - - return { - exchangeAccount, - symbol, - currentAssetPrice, - lowPrice, - highPrice, - }; -} diff --git a/apps/frontend/src/components/grid-bot/create-bot/loading.tsx b/apps/frontend/src/components/grid-bot/create-bot/loading.tsx deleted file mode 100644 index 576db806..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/loading.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import Grid from "@mui/joy/Grid"; -import Skeleton from "@mui/joy/Skeleton"; -import React from "react"; - -export default function Loading() { - return ( - - - - - - - - - - ); -} diff --git a/apps/frontend/src/components/grid-bot/create-bot/page.tsx b/apps/frontend/src/components/grid-bot/create-bot/page.tsx deleted file mode 100644 index 8e6a4c37..00000000 --- a/apps/frontend/src/components/grid-bot/create-bot/page.tsx +++ /dev/null @@ -1,72 +0,0 @@ -"use client"; - -import React from "react"; -import Grid from "@mui/joy/Grid"; -import { TRPCClientErrorBoundary } from "src/ui/errors/suspense"; -import { useIsFirstRender } from "src/hooks/useIsFirstRender"; -import type { GridBotFormChartBarSize } from "src/store/bot-form"; -import { - changeBarSize, - setBotName, - setExchangeAccountId, - setExchangeCode, - setHighPrice, - setLowPrice, - setQuantityPerGrid, - setSymbolId, - selectBarSize, - selectGridLines, - selectSymbolId, -} from "src/store/bot-form"; -import { useAppDispatch, useAppSelector } from "src/store/hooks"; -import { generateBotName } from "src/utils/bot-name-generator"; -import { GridChart } from "./GridChart"; -import { CreateGridBotForm } from "./form"; -import { usePageData } from "./hooks/usePagaData"; - -export default function CreateGridBotPage() { - const { exchangeAccount, symbol, lowPrice, highPrice, currentAssetPrice } = - usePageData(); - const dispatch = useAppDispatch(); - - const isFirstRender = useIsFirstRender(); - if (isFirstRender) { - dispatch(setExchangeAccountId(exchangeAccount.id)); - dispatch(setExchangeCode(exchangeAccount.exchangeCode)); - dispatch(setSymbolId(symbol.symbolId)); - dispatch( - setQuantityPerGrid(symbol.filters.limits.amount?.min?.toString() || ""), - ); - dispatch(setLowPrice(lowPrice)); - dispatch(setHighPrice(highPrice)); - dispatch(setBotName(generateBotName())); - } - - const symbolId = useAppSelector(selectSymbolId); - - const barSize = useAppSelector(selectBarSize); - const handleBarSizeChange = (barSize: GridBotFormChartBarSize) => - dispatch(changeBarSize(barSize)); - - const gridLines = useAppSelector(selectGridLines); - - return ( - - - - - - - - - - - - ); -} diff --git a/apps/frontend/src/components/login/LoginForm.tsx b/apps/frontend/src/components/login/LoginForm.tsx deleted file mode 100644 index 19a7294f..00000000 --- a/apps/frontend/src/components/login/LoginForm.tsx +++ /dev/null @@ -1,77 +0,0 @@ -"use client"; - -import Sheet from "@mui/joy/Sheet"; -import Typography from "@mui/joy/Typography"; -import FormControl from "@mui/joy/FormControl"; -import FormLabel from "@mui/joy/FormLabel"; -import Input from "@mui/joy/Input"; -import Button from "@mui/joy/Button"; -import { useRouter } from "next/navigation"; -import { useState } from "react"; -import { toPage } from "src/utils/next/toPage"; - -export function LoginForm() { - const [email, setEmail] = useState("opentrader"); - const [password, setPassword] = useState(""); - const router = useRouter(); - - const handleLogin = () => { - window.localStorage.setItem("ADMIN_PASSWORD", password); - router.replace(toPage("grid-bot")); - }; - - return ( - - - Welcome Trader! - - Sign in to continue. - - - Username - - setEmail(e.target.value)} - placeholder="username" - type="text" - value={email} - /> - - - - Password - - setPassword(e.target.value)} - placeholder="password" - type="password" - value={password} - /> - - - - - ); -} diff --git a/apps/frontend/src/hooks/useIsFirstRender.ts b/apps/frontend/src/hooks/useIsFirstRender.ts deleted file mode 100644 index 302b5a9d..00000000 --- a/apps/frontend/src/hooks/useIsFirstRender.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { useRef } from "react"; - -export function useIsFirstRender(): boolean { - const isFirst = useRef(true); - - if (isFirst.current) { - isFirst.current = false; - - return true; - } - - return isFirst.current; -} diff --git a/apps/frontend/src/hooks/useIsStale.ts b/apps/frontend/src/hooks/useIsStale.ts deleted file mode 100644 index adfd4063..00000000 --- a/apps/frontend/src/hooks/useIsStale.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { useState } from "react"; - -export function useIsStale(value: T) { - const [prevValue, setPrevValue] = useState(value); - if (value !== prevValue) { - setPrevValue(value); - - return true; - } - - return false; -} diff --git a/apps/frontend/src/lib/react-query/client.ts b/apps/frontend/src/lib/react-query/client.ts deleted file mode 100644 index 9fd68f57..00000000 --- a/apps/frontend/src/lib/react-query/client.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { QueryClient } from "@tanstack/react-query"; - -export const rqc = new QueryClient(); diff --git a/apps/frontend/src/lib/trpc/client.ts b/apps/frontend/src/lib/trpc/client.ts deleted file mode 100644 index 6e074b99..00000000 --- a/apps/frontend/src/lib/trpc/client.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { AppRouter } from "@opentrader/trpc"; -// 👆 **type-only** import -import { createTRPCReact } from "@trpc/react-query"; - -export const tClient = createTRPCReact({}); diff --git a/apps/frontend/src/lib/trpc/getBaseUrl.ts b/apps/frontend/src/lib/trpc/getBaseUrl.ts deleted file mode 100644 index 470368ef..00000000 --- a/apps/frontend/src/lib/trpc/getBaseUrl.ts +++ /dev/null @@ -1,28 +0,0 @@ -export function getBaseUrl(): string { - const isProduction = process.env.NODE_ENV === "production"; - if (isProduction) { - if (typeof window !== "undefined") { - const customURL = localStorage.getItem("APP_URL"); - - // browser should use relative path - return customURL ? customURL : ""; - } - } - - if (process.env.NEXT_PUBLIC_PROCESSOR_ENABLE_TRPC) { - return `${process.env.NEXT_PUBLIC_PROCESSOR_URL}`; - } - - if (typeof window !== "undefined") - // browser should use relative path - return ""; - if (process.env.VERCEL_URL) - // reference for vercel.com - return `https://${process.env.VERCEL_URL}`; - if (process.env.RENDER_INTERNAL_HOSTNAME) - // reference for render.com - return `http://${process.env.RENDER_INTERNAL_HOSTNAME}:${process.env.PORT}`; - - // assume localhost - return `http://localhost:${process.env.PORT ?? 3000}`; -} diff --git a/apps/frontend/src/lib/trpc/index.ts b/apps/frontend/src/lib/trpc/index.ts deleted file mode 100644 index dc5bb0a1..00000000 --- a/apps/frontend/src/lib/trpc/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -import superjson from "superjson"; -import { createTRPCProxyClient, httpBatchLink } from "@trpc/client"; -import type { AppRouter } from "@opentrader/trpc"; -import { getBaseUrl } from "src/lib/trpc/getBaseUrl"; -// 👆 **type-only** import - -const url = `${getBaseUrl()}/api/trpc`; - -// @todo remove this and use instead the client provided from `lib/trpc/client.ts` and `lib/trpc/server.ts` -export const trpc = createTRPCProxyClient({ - transformer: superjson, - links: [ - httpBatchLink({ - url, - // You can pass any HTTP headers you wish here - async headers() { - return { - // authorization: getAuthCookie(), - }; - }, - }), - ], -}); diff --git a/apps/frontend/src/lib/trpc/server.ts b/apps/frontend/src/lib/trpc/server.ts deleted file mode 100644 index 9170fb31..00000000 --- a/apps/frontend/src/lib/trpc/server.ts +++ /dev/null @@ -1,12 +0,0 @@ -import "server-only"; -import { appRouter } from "@opentrader/trpc"; - -export const tServer = appRouter.createCaller({ - user: { - id: 1, - password: "huitebe", - email: "nu@nahui.su", - displayName: null, - role: "Admin", // @todo remove context - }, -}); diff --git a/apps/frontend/src/lib/trpc/types.ts b/apps/frontend/src/lib/trpc/types.ts deleted file mode 100644 index 6e17d80c..00000000 --- a/apps/frontend/src/lib/trpc/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { inferRouterInputs, inferRouterOutputs } from "@trpc/server"; -import type { AppRouter } from "@opentrader/trpc"; -// 👆 **type-only** import - -// @see https://trpc.io/docs/client/vanilla/infer-types -export type RouterInput = inferRouterInputs; -export type RouterOutput = inferRouterOutputs; diff --git a/apps/frontend/src/providers/StoreProvider.tsx b/apps/frontend/src/providers/StoreProvider.tsx deleted file mode 100644 index 7b148f8d..00000000 --- a/apps/frontend/src/providers/StoreProvider.tsx +++ /dev/null @@ -1,13 +0,0 @@ -"use client"; - -import type { FC, ReactNode } from "react"; -import { Provider } from "react-redux"; -import { store } from "src/store"; - -type StoreProviderProps = { - children: ReactNode; -}; - -export const StoreProvider: FC = ({ children }) => { - return {children}; -}; diff --git a/apps/frontend/src/providers/ThemeProvider/EmotionCache.tsx b/apps/frontend/src/providers/ThemeProvider/EmotionCache.tsx deleted file mode 100644 index 75c94678..00000000 --- a/apps/frontend/src/providers/ThemeProvider/EmotionCache.tsx +++ /dev/null @@ -1,99 +0,0 @@ -"use client"; -import * as React from "react"; -import createCache from "@emotion/cache"; -import { useServerInsertedHTML } from "next/navigation"; -import { CacheProvider as DefaultCacheProvider } from "@emotion/react"; -import type { - EmotionCache, - Options as OptionsOfCreateCache, -} from "@emotion/cache"; - -export type NextAppDirEmotionCacheProviderProps = { - // This is the options passed to createCache() from 'import createCache from "@emotion/cache"' - options: Omit; - // Default: 'import { CacheProvider } from "@emotion/react"' - CacheProvider?: (props: { - value: EmotionCache; - children: React.ReactNode; - }) => JSX.Element | null; - children: React.ReactNode; -}; - -// Adapted from https://github.com/garronej/tss-react/blob/main/src/next/appDir.tsx -export default function NextAppDirEmotionCacheProvider( - props: NextAppDirEmotionCacheProviderProps, -) { - const { options, CacheProvider = DefaultCacheProvider, children } = props; - - const [registry] = React.useState(() => { - const cache = createCache(options); - cache.compat = true; - // eslint-disable-next-line @typescript-eslint/unbound-method -- need better typing - const prevInsert = cache.insert; - let inserted: { name: string; isGlobal: boolean }[] = []; - cache.insert = (...args) => { - const [selector, serialized] = args; - - if (cache.inserted[serialized.name] === undefined) { - inserted.push({ - name: serialized.name, - isGlobal: !selector, - }); - } - return prevInsert(...args); - }; - const flush = () => { - const prevInserted = inserted; - inserted = []; - return prevInserted; - }; - return { cache, flush }; - }); - - useServerInsertedHTML(() => { - const inserted = registry.flush(); - if (inserted.length === 0) { - return null; - } - let styles = ""; - let dataEmotionAttribute = registry.cache.key; - - const globals: { - name: string; - style: string; - }[] = []; - - inserted.forEach(({ name, isGlobal }) => { - const style = registry.cache.inserted[name]; - - if (typeof style !== "boolean") { - if (isGlobal) { - globals.push({ name, style }); - } else { - styles += style; - dataEmotionAttribute += ` ${name}`; - } - } - }); - - return ( - <> - {globals.map(({ name, style }) => ( -