Compare commits
No commits in common. "dev" and "old-1" have entirely different histories.
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
2
.idea/discord.xml
generated
2
.idea/discord.xml
generated
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="DiscordProjectSettings">
|
<component name="DiscordProjectSettings">
|
||||||
<option name="show" value="PROJECT" />
|
<option name="show" value="PROJECT_FILES" />
|
||||||
<option name="description" value="" />
|
<option name="description" value="" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
6
.idea/git_toolbox_blame.xml
generated
6
.idea/git_toolbox_blame.xml
generated
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="GitToolBoxBlameSettings">
|
|
||||||
<option name="version" value="2" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
15
.idea/git_toolbox_prj.xml
generated
15
.idea/git_toolbox_prj.xml
generated
@ -1,15 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="GitToolBoxProjectSettings">
|
|
||||||
<option name="commitMessageIssueKeyValidationOverride">
|
|
||||||
<BoolValueOverride>
|
|
||||||
<option name="enabled" value="true" />
|
|
||||||
</BoolValueOverride>
|
|
||||||
</option>
|
|
||||||
<option name="commitMessageValidationEnabledOverride">
|
|
||||||
<BoolValueOverride>
|
|
||||||
<option name="enabled" value="true" />
|
|
||||||
</BoolValueOverride>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
10
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
10
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<Languages>
|
||||||
|
<language minSize="86" name="TypeScript" />
|
||||||
|
</Languages>
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
3
.idea/modules.xml
generated
3
.idea/modules.xml
generated
@ -2,8 +2,7 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/../neptune-back/.idea/neptune-backend.iml" filepath="$PROJECT_DIR$/../neptune-back/.idea/neptune-backend.iml" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/brief-07-front.iml" filepath="$PROJECT_DIR$/.idea/brief-07-front.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/neptune-front.iml" filepath="$PROJECT_DIR$/.idea/neptune-front.iml" />
|
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
@ -8,6 +8,5 @@
|
|||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="module" module-name="neptune-backend" />
|
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
6
.idea/nx-console.xml
generated
6
.idea/nx-console.xml
generated
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="NxConsoleProjectSettingsProvider">
|
|
||||||
<option name="workspacePath" value="" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
1
.idea/vcs.xml
generated
1
.idea/vcs.xml
generated
@ -2,6 +2,5 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="" vcs="Git" />
|
<mapping directory="" vcs="Git" />
|
||||||
<mapping directory="$PROJECT_DIR$/../neptune-back" vcs="Git" />
|
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
21
.idea/webResources.xml
generated
21
.idea/webResources.xml
generated
@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="WebResourcesPaths">
|
|
||||||
<contentEntries>
|
|
||||||
<entry url="file://$PROJECT_DIR$/../neptune-back">
|
|
||||||
<entryData>
|
|
||||||
<resourceRoots>
|
|
||||||
<path value="file://$PROJECT_DIR$/../neptune-back" />
|
|
||||||
</resourceRoots>
|
|
||||||
</entryData>
|
|
||||||
</entry>
|
|
||||||
<entry url="file://$PROJECT_DIR$">
|
|
||||||
<entryData>
|
|
||||||
<resourceRoots>
|
|
||||||
<path value="file://$PROJECT_DIR$" />
|
|
||||||
</resourceRoots>
|
|
||||||
</entryData>
|
|
||||||
</entry>
|
|
||||||
</contentEntries>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
155
.idea/workspace.xml
generated
155
.idea/workspace.xml
generated
@ -1,155 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="AutoImportSettings">
|
|
||||||
<option name="autoReloadType" value="SELECTIVE" />
|
|
||||||
</component>
|
|
||||||
<component name="ChangeListManager">
|
|
||||||
<list default="true" id="fe5a67da-16c2-44c1-97cf-5ff76c380f48" name="Changes" comment="">
|
|
||||||
<change beforePath="$PROJECT_DIR$/../neptune-back/prisma/seed.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../neptune-back/prisma/seed.ts" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
|
||||||
</list>
|
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
||||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
||||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
||||||
</component>
|
|
||||||
<component name="Git.Settings">
|
|
||||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/../neptune-back" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectColorInfo">{
|
|
||||||
"associatedIndex": 0
|
|
||||||
}</component>
|
|
||||||
<component name="ProjectId" id="2oC9EyMrMXnN5JRY3d8EUK3Fg2I" />
|
|
||||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
|
||||||
<component name="ProjectViewState">
|
|
||||||
<option name="hideEmptyMiddlePackages" value="true" />
|
|
||||||
<option name="showLibraryContents" value="true" />
|
|
||||||
</component>
|
|
||||||
<component name="PropertiesComponent">{
|
|
||||||
"keyToString": {
|
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
||||||
"RunOnceActivity.git.unshallow": "true",
|
|
||||||
"last_opened_file_path": "/home/avnyr/monoliths/neptune-back",
|
|
||||||
"node.js.detected.package.eslint": "true",
|
|
||||||
"node.js.detected.package.tslint": "true",
|
|
||||||
"node.js.selected.package.eslint": "(autodetect)",
|
|
||||||
"node.js.selected.package.tslint": "(autodetect)",
|
|
||||||
"nodejs_package_manager_path": "pnpm",
|
|
||||||
"npm.dev.executor": "Run",
|
|
||||||
"settings.editor.selected.configurable": "preferences.lookFeel",
|
|
||||||
"ts.external.directory.path": "/home/avnyr/monoliths/neptune-front/node_modules/typescript/lib",
|
|
||||||
"vue.rearranger.settings.migration": "true"
|
|
||||||
}
|
|
||||||
}</component>
|
|
||||||
<component name="RecentsManager">
|
|
||||||
<key name="MoveFile.RECENT_KEYS">
|
|
||||||
<recent name="$PROJECT_DIR$/public" />
|
|
||||||
</key>
|
|
||||||
</component>
|
|
||||||
<component name="RunManager">
|
|
||||||
<configuration name="dev" type="js.build_tools.npm" nameIsGenerated="true">
|
|
||||||
<package-json value="$PROJECT_DIR$/package.json" />
|
|
||||||
<command value="run" />
|
|
||||||
<scripts>
|
|
||||||
<script value="dev" />
|
|
||||||
</scripts>
|
|
||||||
<node-interpreter value="project" />
|
|
||||||
<package-manager value="$USER_HOME$/.local/share/pnpm/pnpm" />
|
|
||||||
<envs />
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
||||||
<component name="SharedIndexes">
|
|
||||||
<attachedChunks>
|
|
||||||
<set>
|
|
||||||
<option value="bundled-js-predefined-d6986cc7102b-e768b9ed790e-JavaScript-WS-243.21565.180" />
|
|
||||||
</set>
|
|
||||||
</attachedChunks>
|
|
||||||
</component>
|
|
||||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
|
||||||
<component name="TaskManager">
|
|
||||||
<task active="true" id="Default" summary="Default task">
|
|
||||||
<changelist id="fe5a67da-16c2-44c1-97cf-5ff76c380f48" name="Changes" comment="" />
|
|
||||||
<created>1730362584431</created>
|
|
||||||
<option name="number" value="Default" />
|
|
||||||
<option name="presentableId" value="Default" />
|
|
||||||
<updated>1730362584431</updated>
|
|
||||||
<workItem from="1730362585545" duration="2622000" />
|
|
||||||
<workItem from="1730365668445" duration="599000" />
|
|
||||||
<workItem from="1730370820744" duration="1688000" />
|
|
||||||
<workItem from="1730715257858" duration="38000" />
|
|
||||||
<workItem from="1730971311881" duration="4339000" />
|
|
||||||
<workItem from="1732021386744" duration="27000" />
|
|
||||||
<workItem from="1732021424352" duration="4000" />
|
|
||||||
<workItem from="1732028162494" duration="139000" />
|
|
||||||
<workItem from="1732110655402" duration="2406000" />
|
|
||||||
<workItem from="1732115490707" duration="1304000" />
|
|
||||||
<workItem from="1732177377647" duration="212000" />
|
|
||||||
<workItem from="1732177642993" duration="25000" />
|
|
||||||
<workItem from="1732177670017" duration="26000" />
|
|
||||||
<workItem from="1732177712103" duration="20000" />
|
|
||||||
<workItem from="1732177736286" duration="34000" />
|
|
||||||
<workItem from="1732202348717" duration="1808000" />
|
|
||||||
<workItem from="1732268531361" duration="8833000" />
|
|
||||||
<workItem from="1732453974909" duration="11758000" />
|
|
||||||
<workItem from="1732526630314" duration="3449000" />
|
|
||||||
<workItem from="1732646974158" duration="1446000" />
|
|
||||||
<workItem from="1732696522710" duration="884000" />
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00001" summary="Remove IDE configuration files and add new selling feature Removed unnecessary IntelliJ IDEA (`.idea`) configuration files to clean up the repository. Added new sell-related functionality including the SellCryptoPage, SellModal, SellForm, and updated relevant types and UI components.">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1732269965774</created>
|
|
||||||
<option name="number" value="00001" />
|
|
||||||
<option name="presentableId" value="LOCAL-00001" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1732269965774</updated>
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00002" summary="Enable user crypto amount selection and update deployment docs Added the ability to select user crypto amounts in the user service. Removed commented-out code in the offer controller for clarity. Updated the README with deployment and production instructions.">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1732270010458</created>
|
|
||||||
<option name="number" value="00002" />
|
|
||||||
<option name="presentableId" value="LOCAL-00002" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1732270010458</updated>
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00003" summary="Fix offer retrieval method and add GDPR acknowledgment Return the result from `getOffersById` method to fix route handling. Add `id` field in offers selection query and introduce `gdpr_acknowledgement` to the user model and mock data for GDPR compliance.">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1732488599143</created>
|
|
||||||
<option name="number" value="00003" />
|
|
||||||
<option name="presentableId" value="LOCAL-00003" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1732488599143</updated>
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00004" summary="Add defaultCryptoId prop to SellForm and enhance usability Introduced a new defaultCryptoId prop for the SellForm component to pre-select a cryptocurrency on mount. Adjusted responsive layout and usability for various components including headers, modals, and navigation links. Ensured better user feedback and message clarity for login and registration processes.">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1732488612776</created>
|
|
||||||
<option name="number" value="00004" />
|
|
||||||
<option name="presentableId" value="LOCAL-00004" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1732488612776</updated>
|
|
||||||
</task>
|
|
||||||
<task id="LOCAL-00005" summary="Some ide config files and libs changes...">
|
|
||||||
<option name="closed" value="true" />
|
|
||||||
<created>1732647552711</created>
|
|
||||||
<option name="number" value="00005" />
|
|
||||||
<option name="presentableId" value="LOCAL-00005" />
|
|
||||||
<option name="project" value="LOCAL" />
|
|
||||||
<updated>1732647552711</updated>
|
|
||||||
</task>
|
|
||||||
<option name="localTasksCounter" value="6" />
|
|
||||||
<servers />
|
|
||||||
</component>
|
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
|
||||||
<option name="version" value="3" />
|
|
||||||
</component>
|
|
||||||
<component name="VcsManagerConfiguration">
|
|
||||||
<option name="CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT" value="false" />
|
|
||||||
<option name="CHECK_NEW_TODO" value="false" />
|
|
||||||
<MESSAGE value="Remove IDE configuration files and add new selling feature Removed unnecessary IntelliJ IDEA (`.idea`) configuration files to clean up the repository. Added new sell-related functionality including the SellCryptoPage, SellModal, SellForm, and updated relevant types and UI components." />
|
|
||||||
<MESSAGE value="Enable user crypto amount selection and update deployment docs Added the ability to select user crypto amounts in the user service. Removed commented-out code in the offer controller for clarity. Updated the README with deployment and production instructions." />
|
|
||||||
<MESSAGE value="Fix offer retrieval method and add GDPR acknowledgment Return the result from `getOffersById` method to fix route handling. Add `id` field in offers selection query and introduce `gdpr_acknowledgement` to the user model and mock data for GDPR compliance." />
|
|
||||||
<MESSAGE value="Add defaultCryptoId prop to SellForm and enhance usability Introduced a new defaultCryptoId prop for the SellForm component to pre-select a cryptocurrency on mount. Adjusted responsive layout and usability for various components including headers, modals, and navigation links. Ensured better user feedback and message clarity for login and registration processes." />
|
|
||||||
<MESSAGE value="Some ide config files and libs changes..." />
|
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="Some ide config files and libs changes..." />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
13
README.md
13
README.md
@ -1,16 +1,3 @@
|
|||||||
# neptune-front
|
# neptune-front
|
||||||
|
|
||||||
The project to validate my DWWM diploma on the front end.
|
The project to validate my DWWM diploma on the front end.
|
||||||
|
|
||||||
## Déploiement
|
|
||||||
- Configurer les variables d'environnements
|
|
||||||
### En développement
|
|
||||||
```shell
|
|
||||||
pnpm dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### En production
|
|
||||||
```shell
|
|
||||||
pnpm build
|
|
||||||
pnpm start
|
|
||||||
```
|
|
@ -5,7 +5,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --turbo",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
@ -41,7 +41,6 @@
|
|||||||
"@radix-ui/react-toggle": "^1.1.0",
|
"@radix-ui/react-toggle": "^1.1.0",
|
||||||
"@radix-ui/react-toggle-group": "^1.1.0",
|
"@radix-ui/react-toggle-group": "^1.1.0",
|
||||||
"@radix-ui/react-tooltip": "^1.1.4",
|
"@radix-ui/react-tooltip": "^1.1.4",
|
||||||
"@tanstack/react-query": "^5.60.2",
|
|
||||||
"@tanstack/react-table": "^8.20.5",
|
"@tanstack/react-table": "^8.20.5",
|
||||||
"axios": "^1.7.7",
|
"axios": "^1.7.7",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
@ -53,7 +52,7 @@
|
|||||||
"input-otp": "^1.4.1",
|
"input-otp": "^1.4.1",
|
||||||
"lightweight-charts": "^4.2.1",
|
"lightweight-charts": "^4.2.1",
|
||||||
"lucide-react": "^0.395.0",
|
"lucide-react": "^0.395.0",
|
||||||
"next": "14.2.18",
|
"next": "14.2.10",
|
||||||
"next-themes": "^0.3.0",
|
"next-themes": "^0.3.0",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-day-picker": "^8.10.1",
|
"react-day-picker": "^8.10.1",
|
||||||
|
108
pnpm-lock.yaml
generated
108
pnpm-lock.yaml
generated
@ -95,9 +95,6 @@ importers:
|
|||||||
'@radix-ui/react-tooltip':
|
'@radix-ui/react-tooltip':
|
||||||
specifier: ^1.1.4
|
specifier: ^1.1.4
|
||||||
version: 1.1.4(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 1.1.4(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
'@tanstack/react-query':
|
|
||||||
specifier: ^5.60.2
|
|
||||||
version: 5.60.2(react@18.3.1)
|
|
||||||
'@tanstack/react-table':
|
'@tanstack/react-table':
|
||||||
specifier: ^8.20.5
|
specifier: ^8.20.5
|
||||||
version: 8.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 8.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
@ -132,8 +129,8 @@ importers:
|
|||||||
specifier: ^0.395.0
|
specifier: ^0.395.0
|
||||||
version: 0.395.0(react@18.3.1)
|
version: 0.395.0(react@18.3.1)
|
||||||
next:
|
next:
|
||||||
specifier: 14.2.18
|
specifier: 14.2.10
|
||||||
version: 14.2.18(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 14.2.10(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
next-themes:
|
next-themes:
|
||||||
specifier: ^0.3.0
|
specifier: ^0.3.0
|
||||||
version: 0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
@ -545,59 +542,59 @@ packages:
|
|||||||
'@jridgewell/trace-mapping@0.3.25':
|
'@jridgewell/trace-mapping@0.3.25':
|
||||||
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
|
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
|
||||||
|
|
||||||
'@next/env@14.2.18':
|
'@next/env@14.2.10':
|
||||||
resolution: {integrity: sha512-2vWLOUwIPgoqMJKG6dt35fVXVhgM09tw4tK3/Q34GFXDrfiHlG7iS33VA4ggnjWxjiz9KV5xzfsQzJX6vGAekA==}
|
resolution: {integrity: sha512-dZIu93Bf5LUtluBXIv4woQw2cZVZ2DJTjax5/5DOs3lzEOeKLy7GxRSr4caK9/SCPdaW6bCgpye6+n4Dh9oJPw==}
|
||||||
|
|
||||||
'@next/swc-darwin-arm64@14.2.18':
|
'@next/swc-darwin-arm64@14.2.10':
|
||||||
resolution: {integrity: sha512-tOBlDHCjGdyLf0ube/rDUs6VtwNOajaWV+5FV/ajPgrvHeisllEdymY/oDgv2cx561+gJksfMUtqf8crug7sbA==}
|
resolution: {integrity: sha512-V3z10NV+cvMAfxQUMhKgfQnPbjw+Ew3cnr64b0lr8MDiBJs3eLnM6RpGC46nhfMZsiXgQngCJKWGTC/yDcgrDQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@next/swc-darwin-x64@14.2.18':
|
'@next/swc-darwin-x64@14.2.10':
|
||||||
resolution: {integrity: sha512-uJCEjutt5VeJ30jjrHV1VIHCsbMYnEqytQgvREx+DjURd/fmKy15NaVK4aR/u98S1LGTnjq35lRTnRyygglxoA==}
|
resolution: {integrity: sha512-Y0TC+FXbFUQ2MQgimJ/7Ina2mXIKhE7F+GUe1SgnzRmwFY3hX2z8nyVCxE82I2RicspdkZnSWMn4oTjIKz4uzA==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@next/swc-linux-arm64-gnu@14.2.18':
|
'@next/swc-linux-arm64-gnu@14.2.10':
|
||||||
resolution: {integrity: sha512-IL6rU8vnBB+BAm6YSWZewc+qvdL1EaA+VhLQ6tlUc0xp+kkdxQrVqAnh8Zek1ccKHlTDFRyAft0e60gteYmQ4A==}
|
resolution: {integrity: sha512-ZfQ7yOy5zyskSj9rFpa0Yd7gkrBnJTkYVSya95hX3zeBG9E55Z6OTNPn1j2BTFWvOVVj65C3T+qsjOyVI9DQpA==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@next/swc-linux-arm64-musl@14.2.18':
|
'@next/swc-linux-arm64-musl@14.2.10':
|
||||||
resolution: {integrity: sha512-RCaENbIZqKKqTlL8KNd+AZV/yAdCsovblOpYFp0OJ7ZxgLNbV5w23CUU1G5On+0fgafrsGcW+GdMKdFjaRwyYA==}
|
resolution: {integrity: sha512-n2i5o3y2jpBfXFRxDREr342BGIQCJbdAUi/K4q6Env3aSx8erM9VuKXHw5KNROK9ejFSPf0LhoSkU/ZiNdacpQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@next/swc-linux-x64-gnu@14.2.18':
|
'@next/swc-linux-x64-gnu@14.2.10':
|
||||||
resolution: {integrity: sha512-3kmv8DlyhPRCEBM1Vavn8NjyXtMeQ49ID0Olr/Sut7pgzaQTo4h01S7Z8YNE0VtbowyuAL26ibcz0ka6xCTH5g==}
|
resolution: {integrity: sha512-GXvajAWh2woTT0GKEDlkVhFNxhJS/XdDmrVHrPOA83pLzlGPQnixqxD8u3bBB9oATBKB//5e4vpACnx5Vaxdqg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@next/swc-linux-x64-musl@14.2.18':
|
'@next/swc-linux-x64-musl@14.2.10':
|
||||||
resolution: {integrity: sha512-mliTfa8seVSpTbVEcKEXGjC18+TDII8ykW4a36au97spm9XMPqQTpdGPNBJ9RySSFw9/hLuaCMByluQIAnkzlw==}
|
resolution: {integrity: sha512-opFFN5B0SnO+HTz4Wq4HaylXGFV+iHrVxd3YvREUX9K+xfc4ePbRrxqOuPOFjtSuiVouwe6uLeDtabjEIbkmDA==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@next/swc-win32-arm64-msvc@14.2.18':
|
'@next/swc-win32-arm64-msvc@14.2.10':
|
||||||
resolution: {integrity: sha512-J5g0UFPbAjKYmqS3Cy7l2fetFmWMY9Oao32eUsBPYohts26BdrMUyfCJnZFQkX9npYaHNDOWqZ6uV9hSDPw9NA==}
|
resolution: {integrity: sha512-9NUzZuR8WiXTvv+EiU/MXdcQ1XUvFixbLIMNQiVHuzs7ZIFrJDLJDaOF1KaqttoTujpcxljM/RNAOmw1GhPPQQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@next/swc-win32-ia32-msvc@14.2.18':
|
'@next/swc-win32-ia32-msvc@14.2.10':
|
||||||
resolution: {integrity: sha512-Ynxuk4ZgIpdcN7d16ivJdjsDG1+3hTvK24Pp8DiDmIa2+A4CfhJSEHHVndCHok6rnLUzAZD+/UOKESQgTsAZGg==}
|
resolution: {integrity: sha512-fr3aEbSd1GeW3YUMBkWAu4hcdjZ6g4NBl1uku4gAn661tcxd1bHs1THWYzdsbTRLcCKLjrDZlNp6j2HTfrw+Bg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [ia32]
|
cpu: [ia32]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@next/swc-win32-x64-msvc@14.2.18':
|
'@next/swc-win32-x64-msvc@14.2.10':
|
||||||
resolution: {integrity: sha512-dtRGMhiU9TN5nyhwzce+7c/4CCeykYS+ipY/4mIrGzJ71+7zNo55ZxCB7cAVuNqdwtYniFNR2c9OFQ6UdFIMcg==}
|
resolution: {integrity: sha512-UjeVoRGKNL2zfbcQ6fscmgjBAS/inHBh63mjIlfPg/NG8Yn2ztqylXt5qilYb6hoHIwaU2ogHknHWWmahJjgZQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
@ -1249,14 +1246,6 @@ packages:
|
|||||||
'@swc/helpers@0.5.5':
|
'@swc/helpers@0.5.5':
|
||||||
resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==}
|
resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==}
|
||||||
|
|
||||||
'@tanstack/query-core@5.59.20':
|
|
||||||
resolution: {integrity: sha512-e8vw0lf7KwfGe1if4uPFhvZRWULqHjFcz3K8AebtieXvnMOz5FSzlZe3mTLlPuUBcydCnBRqYs2YJ5ys68wwLg==}
|
|
||||||
|
|
||||||
'@tanstack/react-query@5.60.2':
|
|
||||||
resolution: {integrity: sha512-JhpJNxIAPuE0YCpP1Py4zAsgx+zY0V531McRMtQbwVlJF8+mlZwcOPrzGmPV248K8IP+mPbsfxXToVNMNwjUcw==}
|
|
||||||
peerDependencies:
|
|
||||||
react: ^18 || ^19
|
|
||||||
|
|
||||||
'@tanstack/react-table@8.20.5':
|
'@tanstack/react-table@8.20.5':
|
||||||
resolution: {integrity: sha512-WEHopKw3znbUZ61s9i0+i9g8drmDo6asTWbrQh8Us63DAk/M0FkmIqERew6P71HI75ksZ2Pxyuf4vvKh9rAkiA==}
|
resolution: {integrity: sha512-WEHopKw3znbUZ61s9i0+i9g8drmDo6asTWbrQh8Us63DAk/M0FkmIqERew6P71HI75ksZ2Pxyuf4vvKh9rAkiA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@ -2122,8 +2111,8 @@ packages:
|
|||||||
react: ^16.8 || ^17 || ^18
|
react: ^16.8 || ^17 || ^18
|
||||||
react-dom: ^16.8 || ^17 || ^18
|
react-dom: ^16.8 || ^17 || ^18
|
||||||
|
|
||||||
next@14.2.18:
|
next@14.2.10:
|
||||||
resolution: {integrity: sha512-H9qbjDuGivUDEnK6wa+p2XKO+iMzgVgyr9Zp/4Iv29lKa+DYaxJGjOeEA+5VOvJh/M7HLiskehInSa0cWxVXUw==}
|
resolution: {integrity: sha512-sDDExXnh33cY3RkS9JuFEKaS4HmlWmDKP1VJioucCG6z5KuA008DPsDZOzi8UfqEk3Ii+2NCQSJrfbEWtZZfww==}
|
||||||
engines: {node: '>=18.17.0'}
|
engines: {node: '>=18.17.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -3137,33 +3126,33 @@ snapshots:
|
|||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
'@jridgewell/sourcemap-codec': 1.4.15
|
'@jridgewell/sourcemap-codec': 1.4.15
|
||||||
|
|
||||||
'@next/env@14.2.18': {}
|
'@next/env@14.2.10': {}
|
||||||
|
|
||||||
'@next/swc-darwin-arm64@14.2.18':
|
'@next/swc-darwin-arm64@14.2.10':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@next/swc-darwin-x64@14.2.18':
|
'@next/swc-darwin-x64@14.2.10':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@next/swc-linux-arm64-gnu@14.2.18':
|
'@next/swc-linux-arm64-gnu@14.2.10':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@next/swc-linux-arm64-musl@14.2.18':
|
'@next/swc-linux-arm64-musl@14.2.10':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@next/swc-linux-x64-gnu@14.2.18':
|
'@next/swc-linux-x64-gnu@14.2.10':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@next/swc-linux-x64-musl@14.2.18':
|
'@next/swc-linux-x64-musl@14.2.10':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@next/swc-win32-arm64-msvc@14.2.18':
|
'@next/swc-win32-arm64-msvc@14.2.10':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@next/swc-win32-ia32-msvc@14.2.18':
|
'@next/swc-win32-ia32-msvc@14.2.10':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@next/swc-win32-x64-msvc@14.2.18':
|
'@next/swc-win32-x64-msvc@14.2.10':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
@ -3861,13 +3850,6 @@ snapshots:
|
|||||||
'@swc/counter': 0.1.3
|
'@swc/counter': 0.1.3
|
||||||
tslib: 2.6.3
|
tslib: 2.6.3
|
||||||
|
|
||||||
'@tanstack/query-core@5.59.20': {}
|
|
||||||
|
|
||||||
'@tanstack/react-query@5.60.2(react@18.3.1)':
|
|
||||||
dependencies:
|
|
||||||
'@tanstack/query-core': 5.59.20
|
|
||||||
react: 18.3.1
|
|
||||||
|
|
||||||
'@tanstack/react-table@8.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
'@tanstack/react-table@8.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tanstack/table-core': 8.20.5
|
'@tanstack/table-core': 8.20.5
|
||||||
@ -4878,9 +4860,9 @@ snapshots:
|
|||||||
react: 18.3.1
|
react: 18.3.1
|
||||||
react-dom: 18.3.1(react@18.3.1)
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
|
||||||
next@14.2.18(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
next@14.2.10(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@next/env': 14.2.18
|
'@next/env': 14.2.10
|
||||||
'@swc/helpers': 0.5.5
|
'@swc/helpers': 0.5.5
|
||||||
busboy: 1.6.0
|
busboy: 1.6.0
|
||||||
caniuse-lite: 1.0.30001636
|
caniuse-lite: 1.0.30001636
|
||||||
@ -4890,15 +4872,15 @@ snapshots:
|
|||||||
react-dom: 18.3.1(react@18.3.1)
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
styled-jsx: 5.1.1(@babel/core@7.24.7)(react@18.3.1)
|
styled-jsx: 5.1.1(@babel/core@7.24.7)(react@18.3.1)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@next/swc-darwin-arm64': 14.2.18
|
'@next/swc-darwin-arm64': 14.2.10
|
||||||
'@next/swc-darwin-x64': 14.2.18
|
'@next/swc-darwin-x64': 14.2.10
|
||||||
'@next/swc-linux-arm64-gnu': 14.2.18
|
'@next/swc-linux-arm64-gnu': 14.2.10
|
||||||
'@next/swc-linux-arm64-musl': 14.2.18
|
'@next/swc-linux-arm64-musl': 14.2.10
|
||||||
'@next/swc-linux-x64-gnu': 14.2.18
|
'@next/swc-linux-x64-gnu': 14.2.10
|
||||||
'@next/swc-linux-x64-musl': 14.2.18
|
'@next/swc-linux-x64-musl': 14.2.10
|
||||||
'@next/swc-win32-arm64-msvc': 14.2.18
|
'@next/swc-win32-arm64-msvc': 14.2.10
|
||||||
'@next/swc-win32-ia32-msvc': 14.2.18
|
'@next/swc-win32-ia32-msvc': 14.2.10
|
||||||
'@next/swc-win32-x64-msvc': 14.2.18
|
'@next/swc-win32-x64-msvc': 14.2.10
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@babel/core'
|
- '@babel/core'
|
||||||
- babel-plugin-macros
|
- babel-plugin-macros
|
||||||
|
@ -10,6 +10,7 @@ import { useEffect, useState } from "react";
|
|||||||
export default function DashboardPage() {
|
export default function DashboardPage() {
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||||
const [cryptosList, setCryptosList] = useState<ICryptoInWalletInfo[]>([]);
|
const [cryptosList, setCryptosList] = useState<ICryptoInWalletInfo[]>([]);
|
||||||
|
//FIX the loop
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
ApiRequest.authenticated.get
|
ApiRequest.authenticated.get
|
||||||
|
@ -14,7 +14,7 @@ import type React from "react";
|
|||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Neptune Crypto",
|
title: "Neptune Crypto",
|
||||||
description: "A fictive app",
|
description: "A fictive app",
|
||||||
icons: "/neptune.svg",
|
icons: "neptune.svg",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
@ -27,14 +27,14 @@ export default function RootLayout({
|
|||||||
<body className={"w-full min-h-screen flex flex-col items-center justify-between"}>
|
<body className={"w-full min-h-screen flex flex-col items-center justify-between"}>
|
||||||
<Providers>
|
<Providers>
|
||||||
<Header>
|
<Header>
|
||||||
<nav className="flex flex-row flex-wrap md:flex-nowrap gap-2">
|
<div className={"flex flex-row flex-wrap md:flex-nowrap gap-2"}>
|
||||||
<Button asChild variant="light">
|
<Button asChild variant={"light"}>
|
||||||
<Link href="/wallet" title={"Go to your wallet"}><p className="lg:text-lg">Wallet</p></Link>
|
<Link href={"/wallet"}><p className={"lg:text-lg"}>Wallet</p></Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button asChild variant="light">
|
<Button asChild variant={"light"}>
|
||||||
<Link href="/dashboard" title={"Go to the crypto explorer"}><p className="lg:text-lg">Explore cryptos</p></Link>
|
<Link href={"/dashboard"}><p className={"lg:text-lg"}>Explore cryptos</p></Link>
|
||||||
</Button>
|
</Button>
|
||||||
</nav>
|
</div>
|
||||||
</Header>
|
</Header>
|
||||||
{children}
|
{children}
|
||||||
<Toaster />
|
<Toaster />
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button"
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input"
|
||||||
import { Bitcoin, DollarSign, LineChart, Lock, Zap } from "lucide-react";
|
import { Bitcoin, DollarSign, LineChart, Lock, Zap } from "lucide-react"
|
||||||
import Link from "next/link";
|
import Link from "next/link"
|
||||||
|
|
||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
return (
|
return (
|
||||||
@ -12,7 +12,7 @@ export default function HomePage() {
|
|||||||
<div className="container px-4 md:px-6">
|
<div className="container px-4 md:px-6">
|
||||||
<div className="flex flex-col items-center space-y-4 text-center">
|
<div className="flex flex-col items-center space-y-4 text-center">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<h1 className="text-3xl font-bold tracking-tighter sm:text-4xl md:text-5xl lg:text-6xl">
|
<h1 className="text-3xl font-bold tracking-tighter sm:text-4xl md:text-5xl lg:text-6xl/none">
|
||||||
Welcome to Neptune Crypto
|
Welcome to Neptune Crypto
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mx-auto max-w-[700px] text-gray-500 md:text-xl dark:text-gray-400">
|
<p className="mx-auto max-w-[700px] text-gray-500 md:text-xl dark:text-gray-400">
|
||||||
@ -23,13 +23,9 @@ export default function HomePage() {
|
|||||||
<Button>Get Started</Button>
|
<Button>Get Started</Button>
|
||||||
<Button variant="outline">Learn More</Button>
|
<Button variant="outline">Learn More</Button>
|
||||||
</div>
|
</div>
|
||||||
<p className="mx-auto max-w-[700px] text-destructive/50 md:text-lg">
|
|
||||||
This website is fictional and for demonstration purposes only.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="w-full py-12 md:py-16 lg:py-20 bg-card rounded">
|
<section className="w-full py-12 md:py-16 lg:py-20 bg-card rounded">
|
||||||
<div className="container px-4 md:px-6 rounded">
|
<div className="container px-4 md:px-6 rounded">
|
||||||
<h2 className="text-3xl font-bold tracking-tighter sm:text-5xl text-center mb-12">Our Features</h2>
|
<h2 className="text-3xl font-bold tracking-tighter sm:text-5xl text-center mb-12">Our Features</h2>
|
||||||
@ -58,13 +54,12 @@ export default function HomePage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="w-full py-12 md:py-24 lg:py-32">
|
<section className="w-full py-12 md:py-24 lg:py-32">
|
||||||
<div className="container px-4 md:px-6">
|
<div className="container px-4 md:px-6">
|
||||||
<div className="flex flex-col items-center justify-center space-y-4 text-center">
|
<div className="flex flex-col items-center justify-center space-y-4 text-center">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<h2 className="text-3xl font-bold tracking-tighter sm:text-5xl">Start Trading Today</h2>
|
<h2 className="text-3xl font-bold tracking-tighter sm:text-5xl">Start Trading Today</h2>
|
||||||
<p className="mx-auto max-w-[600px] text-gray-500 md:text-xl lg:text-base xl:text-xl dark:text-gray-400">
|
<p className="mx-auto max-w-[600px] text-gray-500 md:text-xl/relaxed lg:text-base/relaxed xl:text-xl/relaxed dark:text-gray-400">
|
||||||
Join thousands of traders and investors on our platform. Get started with as little as $10.
|
Join thousands of traders and investors on our platform. Get started with as little as $10.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -75,8 +70,8 @@ export default function HomePage() {
|
|||||||
</Button>
|
</Button>
|
||||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||||
By signing up, you agree to our{" "}
|
By signing up, you agree to our{" "}
|
||||||
<Link title="Go to legal notice" className="underline underline-offset-2" href="/legal">
|
<Link className="underline underline-offset-2" href="#">
|
||||||
Legal Notice
|
Terms & Conditions
|
||||||
</Link>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -85,5 +80,5 @@ export default function HomePage() {
|
|||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
}
|
}
|
@ -1,24 +0,0 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import {OfferList} from "@/components/sub/OfferList";
|
|
||||||
import {SellForm} from "@/components/sell-form";
|
|
||||||
|
|
||||||
|
|
||||||
interface SellCryptoPageProps {
|
|
||||||
params: IParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IParams {
|
|
||||||
cryptoId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function SellCryptoPage({ params }: SellCryptoPageProps) {
|
|
||||||
console.log(params);
|
|
||||||
return (
|
|
||||||
<main className="flex flex-col sm:flex-row items-center justify-center w-full h-full gap-4 p-2 sm:p-4">
|
|
||||||
<section className={"w-full lg:w-1/3 h-full p-0.5 sm:p-2 flex flex-col items-center justify-center gap-4"}>
|
|
||||||
<SellForm defaultCryptoId={params.cryptoId}/>
|
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
}
|
|
@ -14,6 +14,7 @@ export default function WalletPage() {
|
|||||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||||
const [cryptosList, setCryptosList] = useState<ICryptoInWalletInfo[]>([]);
|
const [cryptosList, setCryptosList] = useState<ICryptoInWalletInfo[]>([]);
|
||||||
const userContext = useContext(UserDataContext);
|
const userContext = useContext(UserDataContext);
|
||||||
|
//FIX the loop
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log(userContext?.userData);
|
console.log(userContext?.userData);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
@ -10,89 +9,20 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
import type { IUserData, IUserWallet } from "@/interfaces/userdata.interface";
|
import type { IUserData, IUserWallet } from "@/interfaces/userdata.interface";
|
||||||
|
|
||||||
import { CopyButton } from "@/components/ui/copy-button";
|
import { CopyButton } from "@/components/ui/copy-button";
|
||||||
import type {
|
import {
|
||||||
ICryptoInUserWalletInfo,
|
type ICryptoInUserWalletInfo,
|
||||||
|
ICryptoInWalletInfo,
|
||||||
} from "@/interfaces/crypto.interface";
|
} from "@/interfaces/crypto.interface";
|
||||||
|
import { doDisconnect, getWallet } from "@/services/account.handler";
|
||||||
import { Bitcoin, Fingerprint, Key, Landmark, Unplug, User, Wallet } from "lucide-react";
|
import { Bitcoin, Fingerprint, Key, Landmark, Unplug, User, Wallet } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import type React from "react";
|
import type React from "react";
|
||||||
import { useEffect, useState, useCallback, useMemo } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { EReturnState, type IStandardisedReturn } from "@/interfaces/general.interface";
|
|
||||||
import type { IApiUserAssetsRes } from "@/interfaces/api.interface";
|
|
||||||
import ApiRequest from "@/services/apiRequest";
|
|
||||||
|
|
||||||
export function doDisconnect() {
|
|
||||||
if (typeof window !== "undefined") {
|
|
||||||
window.localStorage.removeItem("sub");
|
|
||||||
//Redirect to homepage
|
|
||||||
window.location.href = "/";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
console.log("Whut ? Why trying to remove an item from the localStorage when running in SSR ?");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getWallet(): Promise<IStandardisedReturn<IApiUserAssetsRes>> {
|
|
||||||
try {
|
|
||||||
const ReqRes =
|
|
||||||
await ApiRequest.authenticated.get.json<IStandardisedReturn<IApiUserAssetsRes>>(
|
|
||||||
"user/my-assets"
|
|
||||||
);
|
|
||||||
console.log(ReqRes.data);
|
|
||||||
|
|
||||||
if (ReqRes.status !== 200) {
|
|
||||||
return {
|
|
||||||
state: EReturnState.clientError,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
state: EReturnState.done,
|
|
||||||
resolved: ReqRes.data,
|
|
||||||
};
|
|
||||||
} catch (err) {
|
|
||||||
return {
|
|
||||||
state: EReturnState.serverError,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function useWallet(userData: IUserData, setUserData: React.Dispatch<React.SetStateAction<IUserData | undefined>>) {
|
|
||||||
const [isLoaded, setIsLoaded] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isLoaded) {
|
|
||||||
getWallet().then((res) => {
|
|
||||||
const wallet: IUserWallet = {
|
|
||||||
uat: Date.now(),
|
|
||||||
update_interval: 30000,
|
|
||||||
owned_cryptos: res.resolved?.UserHasCrypto?.map((el): ICryptoInUserWalletInfo => ({
|
|
||||||
id: el.Crypto.id,
|
|
||||||
name: el.Crypto.name,
|
|
||||||
value: el.Crypto.value,
|
|
||||||
image: el.Crypto.image,
|
|
||||||
quantity: el.Crypto.quantity,
|
|
||||||
owned_amount: el.amount,
|
|
||||||
created_at: el.Crypto.created_at,
|
|
||||||
updated_at: el.Crypto.updated_at,
|
|
||||||
})) || [],
|
|
||||||
};
|
|
||||||
|
|
||||||
delete res.resolved?.UserHasCrypto;
|
|
||||||
setUserData((prev) => ({
|
|
||||||
...prev,
|
|
||||||
...res.resolved,
|
|
||||||
wallet,
|
|
||||||
}) as unknown as IUserData);
|
|
||||||
console.log(userData);
|
|
||||||
setIsLoaded(true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [isLoaded, userData, setUserData]);
|
|
||||||
|
|
||||||
return isLoaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AccountInfo({
|
export function AccountInfo({
|
||||||
userData,
|
userData,
|
||||||
@ -103,43 +33,59 @@ export function AccountInfo({
|
|||||||
setUserData: React.Dispatch<React.SetStateAction<IUserData | undefined>>;
|
setUserData: React.Dispatch<React.SetStateAction<IUserData | undefined>>;
|
||||||
isDisconnected: boolean;
|
isDisconnected: boolean;
|
||||||
}) {
|
}) {
|
||||||
const isLoaded = useWallet(userData, setUserData);
|
const [isLoaded, setIsLoaded] = useState(false);
|
||||||
|
|
||||||
const walletInfo = useMemo(() => (
|
useEffect(() => {
|
||||||
<div className={"flex flex-col md:flex-row gap-2 justify-center md:justify-evenly items-start md:items-center w-full"}>
|
if (!isLoaded) {
|
||||||
<div className={"flex gap-1 justify-start md:justify-center items-center mx-auto w-full md:w-fit"}>
|
getWallet().then((res) => {
|
||||||
<Landmark />
|
const wallet: IUserWallet = {
|
||||||
<p className={"rounded bg-accent text-accent-foreground p-1"}>{userData.dollarAvailables} $</p>
|
uat: Date.now(),
|
||||||
</div>
|
update_interval: 30_000,
|
||||||
<div className={"flex gap-1 justify-start md:justify-center items-center mx-auto w-full md:w-fit"}>
|
owned_cryptos:
|
||||||
<Bitcoin />
|
res.resolved?.UserHasCrypto?.map((el): ICryptoInUserWalletInfo => {
|
||||||
<p className={"rounded bg-accent text-accent-foreground p-1"}>{`You currently have ${userData.wallet.owned_cryptos.length} crypto(s)`}</p>
|
return {
|
||||||
</div>
|
id: el.Crypto.id,
|
||||||
</div>
|
name: el.Crypto.name,
|
||||||
), [userData.dollarAvailables, userData.wallet.owned_cryptos.length]);
|
value: el.Crypto.value,
|
||||||
|
image: el.Crypto.image,
|
||||||
const userInfo = useMemo(() => (
|
quantity: el.Crypto.quantity,
|
||||||
<div className={"flex flex-col gap-3 justify-center items-start mx-auto mt-4"}>
|
owned_amount: el.amount,
|
||||||
<div className={"flex flex-row text-nowrap flex-nowrap gap-1 text-primary"}>
|
created_at: el.Crypto.created_at,
|
||||||
<Fingerprint />
|
updated_at: el.Crypto.updated_at,
|
||||||
<h2>Your identity</h2>
|
};
|
||||||
</div>
|
}) || [],
|
||||||
<div className={"font-light text-xs md:text-sm flex flex-row items-center justify-start gap-1 bg-accent p-2 rounded"}>
|
};
|
||||||
<p>{userData.id}</p>
|
|
||||||
<CopyButton value={userData.id} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
), [userData.id]);
|
|
||||||
|
|
||||||
|
delete res.resolved?.UserHasCrypto;
|
||||||
|
//@ts-ignore
|
||||||
|
setUserData({
|
||||||
|
...userData,
|
||||||
|
...res.resolved,
|
||||||
|
wallet: wallet,
|
||||||
|
});
|
||||||
|
console.log(userData);
|
||||||
|
setIsLoaded(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [isLoaded, userData, setUserData]);
|
||||||
if (isDisconnected) {
|
if (isDisconnected) {
|
||||||
return (
|
return (
|
||||||
<div className={"flex flex-col justify-center items-center h-10 p-2 text-xs mt-2"}>
|
<div className={"flex flex-col justify-center items-center h-10 p-2 text-xs mt-2"}>
|
||||||
<div className={"flex flex-row justify-center items-center gap-1 text-destructive to-red-900 animate-pulse"}>
|
<div
|
||||||
|
className={
|
||||||
|
"flex flex-row justify-center items-center gap-1 text-destructive to-red-900 animate-pulse"
|
||||||
|
}
|
||||||
|
>
|
||||||
<Unplug className={"w-4"} />
|
<Unplug className={"w-4"} />
|
||||||
<p>Disconnected</p>
|
<p>Disconnected</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Link href={"/auth"} className={"hover:text-primary flex justify-evenly items-center gap-1 p-1 text-nowrap"}>
|
<Link
|
||||||
|
href={"/auth"}
|
||||||
|
className={
|
||||||
|
"hover:text-primary flex justify-evenly items-center gap-1 p-1 text-nowrap"
|
||||||
|
}
|
||||||
|
>
|
||||||
<Key className={"w-3"} /> Link account
|
<Key className={"w-3"} /> Link account
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@ -161,8 +107,50 @@ export function AccountInfo({
|
|||||||
<DialogDescription>{userData.pseudo}</DialogDescription>
|
<DialogDescription>{userData.pseudo}</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className={"flex flex-col items-center justify-center w-full"}>
|
<div className={"flex flex-col items-center justify-center w-full"}>
|
||||||
{walletInfo}
|
<div className={"flex flex-col justify-evenly items-center gap-2"}>
|
||||||
{userInfo}
|
<div
|
||||||
|
className={
|
||||||
|
"flex flex-col md:flex-row gap-2 justify-center md:justify-evenly items-start md:items-center w-full"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"flex gap-1 justify-start md:justify-center items-center mx-auto w-full md:w-fit"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Landmark />
|
||||||
|
<p className={"rounded bg-accent text-accent-foreground p-1"}>
|
||||||
|
{userData.dollarAvailables} $
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"flex gap-1 justify-start md:justify-center items-center mx-auto w-full md:w-fit"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Bitcoin />
|
||||||
|
<p className={"rounded bg-accent text-accent-foreground p-1"}>
|
||||||
|
{`You currently have ${userData.wallet.owned_cryptos.length} crypto(s)`}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={"flex flex-col gap-3 justify-center items-start mx-auto mt-4"}
|
||||||
|
>
|
||||||
|
<div className={"flex flex-row text-nowrap flex-nowrap gap-1 text-primary"}>
|
||||||
|
<Fingerprint />
|
||||||
|
<h2>Your identity</h2>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"font-light text-xs md:text-sm flex flex-row items-center justify-start gap-1 bg-accent p-2 rounded"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<p>{userData.id}</p>
|
||||||
|
<CopyButton value={userData.id} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button variant={"secondary"} className={"gap-2 px-2"} asChild>
|
<Button variant={"secondary"} className={"gap-2 px-2"} asChild>
|
||||||
@ -171,7 +159,11 @@ export function AccountInfo({
|
|||||||
<p>My wallet</p>
|
<p>My wallet</p>
|
||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant={"destructive"} className={"gap-2 px-2 mb-2"} onClick={() => doDisconnect()}>
|
<Button
|
||||||
|
variant={"destructive"}
|
||||||
|
className={"gap-2 px-2 mb-2"}
|
||||||
|
onClick={() => doDisconnect()}
|
||||||
|
>
|
||||||
<Unplug />
|
<Unplug />
|
||||||
<p>Disconnect</p>
|
<p>Disconnect</p>
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -64,9 +64,6 @@ const registerSchema = z.object({
|
|||||||
.regex(/[0-9]/, "Password must contain at least one number.")
|
.regex(/[0-9]/, "Password must contain at least one number.")
|
||||||
.regex(/[^a-zA-Z0-9]/, "Password must contain at least one special character.")
|
.regex(/[^a-zA-Z0-9]/, "Password must contain at least one special character.")
|
||||||
.describe("Your account password."),
|
.describe("Your account password."),
|
||||||
|
|
||||||
promoCode: z
|
|
||||||
.string().max(255, "Your promotional code is too long.").optional(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export function AuthForms() {
|
export function AuthForms() {
|
||||||
@ -179,7 +176,7 @@ export function AuthForms() {
|
|||||||
}
|
}
|
||||||
//toast.custom(<ToastBox message={"Login successful ! \n You will be redirected."} type={toastType.success}/>)
|
//toast.custom(<ToastBox message={"Login successful ! \n You will be redirected."} type={toastType.success}/>)
|
||||||
toast({
|
toast({
|
||||||
description: "Login successful ! \n You will be redirected to the home page.",
|
description: "Login successful ! \n You will be redirected.",
|
||||||
});
|
});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@ -248,9 +245,9 @@ export function AuthForms() {
|
|||||||
<p>Register</p>
|
<p>Register</p>
|
||||||
</AutoFormSubmit>
|
</AutoFormSubmit>
|
||||||
<p className="text-gray-500 text-sm">
|
<p className="text-gray-500 text-sm">
|
||||||
By submitting this form, you agree to the{" "}
|
By submitting this form, you agree to our{" "}
|
||||||
<Link title={"Go to legal page"} href="/legal" className="text-primary underline">
|
<Link href="#" className="text-primary underline">
|
||||||
GDPR Compliance Policy & Usage Policy
|
terms and conditions
|
||||||
</Link>
|
</Link>
|
||||||
.
|
.
|
||||||
</p>
|
</p>
|
||||||
|
@ -3,6 +3,7 @@ import type { DefaultValues } from "react-hook-form";
|
|||||||
import type { z } from "zod";
|
import type { z } from "zod";
|
||||||
import type { FieldConfig } from "./types";
|
import type { FieldConfig } from "./types";
|
||||||
|
|
||||||
|
// TODO: This should support recursive ZodEffects but TypeScript doesn't allow circular type definitions.
|
||||||
export type ZodObjectOrWrapped =
|
export type ZodObjectOrWrapped =
|
||||||
| z.ZodObject<any, any>
|
| z.ZodObject<any, any>
|
||||||
| z.ZodEffects<z.ZodObject<any, any>>;
|
| z.ZodEffects<z.ZodObject<any, any>>;
|
||||||
|
@ -4,6 +4,7 @@ import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
|
|||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
FormControl,
|
FormControl,
|
||||||
|
FormDescription,
|
||||||
FormField,
|
FormField,
|
||||||
FormItem,
|
FormItem,
|
||||||
FormLabel,
|
FormLabel,
|
||||||
@ -11,20 +12,21 @@ import {
|
|||||||
} from "@/components/ui/form";
|
} from "@/components/ui/form";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
SelectContent,
|
SelectContent,
|
||||||
SelectItem,
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import { toast } from "@/components/ui/use-toast";
|
import { toast } from "@/components/ui/use-toast";
|
||||||
import type { IApiAllOffersRes } from "@/interfaces/api.interface";
|
import type { IApiAllOffersRes, IApiDoTradeReq } from "@/interfaces/api.interface";
|
||||||
import type { ICryptoInWalletInfo } from "@/interfaces/crypto.interface";
|
import type { ICryptoInWalletInfo } from "@/interfaces/crypto.interface";
|
||||||
import ApiRequest from "@/services/apiRequest";
|
import ApiRequest from "@/services/apiRequest";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { Ban, DollarSign, RefreshCw } from "lucide-react";
|
import { Ban, DollarSign, RefreshCw } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { useEffect, useState } from "react";
|
import { Dispatch, SetStateAction, useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -41,7 +43,6 @@ export function BuyModal(props: Props) {
|
|||||||
ApiRequest.authenticated.get
|
ApiRequest.authenticated.get
|
||||||
.json<IApiAllOffersRes[]>(`offer/crypto/${props.cryptoData.id}`)
|
.json<IApiAllOffersRes[]>(`offer/crypto/${props.cryptoData.id}`)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
console.debug(response)
|
|
||||||
if (response.data) {setOffersList(response.data)}
|
if (response.data) {setOffersList(response.data)}
|
||||||
console.log(`Crypto ${props.cryptoData.name} -> ${response.data.length}`);
|
console.log(`Crypto ${props.cryptoData.name} -> ${response.data.length}`);
|
||||||
setIsLoaded(true);
|
setIsLoaded(true);
|
||||||
@ -156,10 +157,7 @@ export function BuyModal(props: Props) {
|
|||||||
{offersList.length}
|
{offersList.length}
|
||||||
</p>
|
</p>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger value="server">Buy from server{" "}<p
|
<TabsTrigger value="server">Buy from server</TabsTrigger>
|
||||||
className={" ml-1 px-1 bg-primary text-primary-foreground rounded"}>
|
|
||||||
{props.cryptoData.quantity}
|
|
||||||
</p></TabsTrigger>
|
|
||||||
</TabsList>
|
</TabsList>
|
||||||
<TabsContent
|
<TabsContent
|
||||||
value="user"
|
value="user"
|
||||||
@ -176,20 +174,22 @@ export function BuyModal(props: Props) {
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Select an offer</FormLabel>
|
<FormLabel>Select an offer</FormLabel>
|
||||||
<Select defaultValue={offersList[0]?.id} onValueChange={(val) => {
|
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
||||||
console.log(val);
|
<FormControl>
|
||||||
field.onChange(val);
|
|
||||||
}}>
|
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Select an offer to purchase." />
|
<SelectValue placeholder="Select an offer to purchase." />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
|
</FormControl>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{offersList.map((offer) => (
|
{offersList.map((offer) => {
|
||||||
|
if (!offer) return;
|
||||||
|
return (
|
||||||
<SelectItem
|
<SelectItem
|
||||||
value={offer.id}
|
value={offer.id}
|
||||||
key={offer.id}
|
key={offer.id}
|
||||||
>{`${offer.amount}x ${offer.Crypto.name}`}</SelectItem>
|
>{`${offer.amount}x ${offer.Crypto.name} - ${offer.User.pseudo}`}</SelectItem>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
import type {Row} from "@tanstack/react-table";
|
|
||||||
import type {ICryptoInUserWalletInfo} from "@/interfaces/crypto.interface";
|
|
||||||
|
|
||||||
|
|
||||||
interface SellModalProps {
|
|
||||||
row: Row<ICryptoInUserWalletInfo>
|
|
||||||
}
|
|
||||||
export function SellModal({ row }: SellModalProps) {
|
|
||||||
|
|
||||||
}
|
|
@ -10,12 +10,15 @@ import { ViewModal } from "@/components/cryptos/view-modal";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { DataTable } from "@/components/ui/data-table";
|
import { DataTable } from "@/components/ui/data-table";
|
||||||
import type { IUserWallet } from "@/interfaces/userdata.interface";
|
import type { IUserWallet } from "@/interfaces/userdata.interface";
|
||||||
import type {
|
import {
|
||||||
ColumnDef,
|
type ColumnDef,
|
||||||
|
flexRender,
|
||||||
|
getCoreRowModel,
|
||||||
|
useReactTable,
|
||||||
} from "@tanstack/react-table";
|
} from "@tanstack/react-table";
|
||||||
import { ArrowUpDown, MoreHorizontal, Receipt } from "lucide-react";
|
import { ArrowUpDown, MoreHorizontal } from "lucide-react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import Link from "next/link";
|
import { useState } from "react";
|
||||||
|
|
||||||
interface DataTableProps<TData, TValue> {
|
interface DataTableProps<TData, TValue> {
|
||||||
columns: ColumnDef<TData, TValue>[];
|
columns: ColumnDef<TData, TValue>[];
|
||||||
@ -69,8 +72,8 @@ export function WalletTable(props: Props) {
|
|||||||
const payment = row.original;
|
const payment = row.original;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={"flex gap-2"}>
|
||||||
<Link href={`/sell/${row.original.id}`} className={"flex w-fit gap-2 p-2 justify-center items-center rounded hover:bg-card"}><Receipt /> <p className={"hidden sm:block"}>Sell for USD</p></Link>
|
<p className={"font-light italic text-xs"}>Soon here : Sell, History</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -11,11 +11,11 @@ export function Header({
|
|||||||
return (
|
return (
|
||||||
<header
|
<header
|
||||||
className={
|
className={
|
||||||
"flex flex-col md:flex-row justify-between items-center w-full p-1 md:px-3 gap-2 md:py-2 pb-2 border-b-2"
|
"flex flex-col md:flex-row justify-between items-center w-full p-1 md:px-3 md:py-2 pb-2 border-b-2"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Link title={"Return to home page"} href={"/"} className={"flex flex-row justify-center md:justify-start items-center w-fit gap-2"}>
|
<Link href={"/"} className={"flex flex-row justify-center md:justify-start items-center w-fit gap-2"}>
|
||||||
<Image src={"/neptune.svg"} alt={"Logo of Neptune"} width={42} height={42} />
|
<Image src={"neptune.svg"} alt={"Logo of Neptune"} width={42} height={42} />
|
||||||
<h1 className={"font-bold text-xl align-middle text-center text-wrap"}>
|
<h1 className={"font-bold text-xl align-middle text-center text-wrap"}>
|
||||||
{title || "Neptune"}
|
{title || "Neptune"}
|
||||||
</h1>
|
</h1>
|
||||||
|
@ -4,16 +4,11 @@ import { Header } from "@/components/header";
|
|||||||
import { ThemeProvider } from "@/components/providers/theme-provider";
|
import { ThemeProvider } from "@/components/providers/theme-provider";
|
||||||
import { UserDataProvider } from "@/components/providers/userdata-provider";
|
import { UserDataProvider } from "@/components/providers/userdata-provider";
|
||||||
import type React from "react";
|
import type React from "react";
|
||||||
import {QueryProvider} from "@/components/providers/query-provider";
|
|
||||||
|
|
||||||
export function Providers({ children }: { children: React.ReactNode }) {
|
export function Providers({ children }: { children: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
||||||
<QueryProvider>
|
<UserDataProvider>{children}</UserDataProvider>
|
||||||
<UserDataProvider>
|
|
||||||
{children}
|
|
||||||
</UserDataProvider>
|
|
||||||
</QueryProvider>
|
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
"use client"
|
|
||||||
import type {ReactNode} from "react";
|
|
||||||
import {QueryClient, QueryClientProvider} from "@tanstack/react-query";
|
|
||||||
|
|
||||||
|
|
||||||
interface QueryProviderProps {
|
|
||||||
children: ReactNode;
|
|
||||||
}
|
|
||||||
export function QueryProvider({ children }: QueryProviderProps) {
|
|
||||||
return (<QueryClientProvider client={new QueryClient()}>
|
|
||||||
{ children }
|
|
||||||
</QueryClientProvider>)
|
|
||||||
}
|
|
@ -1,199 +0,0 @@
|
|||||||
"use client";
|
|
||||||
import * as z from "zod";
|
|
||||||
import ApiRequest from "@/services/apiRequest";
|
|
||||||
import { toast } from "@/components/ui/use-toast";
|
|
||||||
import * as React from "react";
|
|
||||||
import { useForm } from "react-hook-form";
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
|
||||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
|
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import type { IUserWalletCryptos } from "@/interfaces/crypto.interface";
|
|
||||||
import type { IApiUserAssetsRes } from "@/interfaces/api.interface";
|
|
||||||
import { Slider } from "@/components/ui/slider";
|
|
||||||
import { DollarSign, Equal, X } from "lucide-react";
|
|
||||||
import { Card } from "@/components/ui/card";
|
|
||||||
|
|
||||||
interface SellFormProps {
|
|
||||||
defaultCryptoId?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SellForm({ defaultCryptoId }: SellFormProps) {
|
|
||||||
const [currentWallet, setCurrentWallet] = useState<IUserWalletCryptos[]>();
|
|
||||||
const [sliderValue, setSliderValue] = useState(0);
|
|
||||||
const [quantity, setQuantity] = useState(0);
|
|
||||||
const [selectedCrypto, setSelectedCrypto] = useState<string>();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
async function fetchAssets() {
|
|
||||||
const res = await ApiRequest.authenticated.get.json<IApiUserAssetsRes>("user/my-assets");
|
|
||||||
setCurrentWallet(res.data.UserHasCrypto);
|
|
||||||
}
|
|
||||||
fetchAssets();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (defaultCryptoId) {
|
|
||||||
const maxShares = getMaxSharesForCrypto(defaultCryptoId);
|
|
||||||
setSliderValue(maxShares);
|
|
||||||
setSelectedCrypto(defaultCryptoId);
|
|
||||||
setQuantity(1);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
function getMaxSharesForCrypto(cryptoId: string) {
|
|
||||||
return currentWallet?.find((crypto) => crypto.Crypto.id === cryptoId)?.amount || 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCryptoValue(cryptoId: string) {
|
|
||||||
return currentWallet?.find((crypto) => crypto.Crypto.id === cryptoId)?.Crypto.value || 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCryptoName(cryptoId: string) {
|
|
||||||
return currentWallet?.find((crypto) => crypto.Crypto.id === cryptoId)?.Crypto.name || "";
|
|
||||||
}
|
|
||||||
|
|
||||||
const sellToUserSchema = z.object({
|
|
||||||
cryptoId: z.string({ required_error: "You should select a crypto from your wallet." }).uuid(),
|
|
||||||
amount: z.number({
|
|
||||||
required_error: "You should select an amount of the assets that you want to sell.",
|
|
||||||
}).max(sliderValue),
|
|
||||||
});
|
|
||||||
|
|
||||||
async function onSellToUserSubmit(data: z.infer<typeof sellToUserSchema>) {
|
|
||||||
const res = await ApiRequest.authenticated.post.json("offer/create", {
|
|
||||||
id_crypto: data.cryptoId,
|
|
||||||
amount: data.amount,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res.status !== 201) {
|
|
||||||
toast({
|
|
||||||
title: "An error occurred!",
|
|
||||||
description: (
|
|
||||||
<pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
|
|
||||||
<code className="text-white text-wrap">{JSON.stringify(res.statusText, null, 2)}</code>
|
|
||||||
</pre>
|
|
||||||
),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(res);
|
|
||||||
toast({
|
|
||||||
title: "Transaction accepted.",
|
|
||||||
description: <p>The page is going to reload.</p>,
|
|
||||||
});
|
|
||||||
setTimeout(() => location.reload(), 1_500);
|
|
||||||
|
|
||||||
toast({
|
|
||||||
title: "You submitted the following values:",
|
|
||||||
description: (
|
|
||||||
<pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
|
|
||||||
<code className="text-white">{JSON.stringify(data, null, 2)}</code>
|
|
||||||
</pre>
|
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const sellToUserForm = useForm<z.infer<typeof sellToUserSchema>>({
|
|
||||||
resolver: zodResolver(sellToUserSchema),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!currentWallet) {
|
|
||||||
return (
|
|
||||||
<Card>
|
|
||||||
<div className="flex items-center justify-center p-2">
|
|
||||||
<p>Loading...</p>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Form {...sellToUserForm}>
|
|
||||||
<form onSubmit={sellToUserForm.handleSubmit(onSellToUserSubmit)} className="w-full space-y-6">
|
|
||||||
<FormField
|
|
||||||
control={sellToUserForm.control}
|
|
||||||
name="cryptoId"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem
|
|
||||||
onChange={(event) => {
|
|
||||||
// @ts-ignore
|
|
||||||
const maxShares = getMaxSharesForCrypto(event.target.value as string);
|
|
||||||
setSliderValue(maxShares);
|
|
||||||
setQuantity(maxShares);
|
|
||||||
// @ts-ignore
|
|
||||||
setSelectedCrypto(event.target.value as string);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FormLabel>Sell shares of your wallet</FormLabel>
|
|
||||||
<Select
|
|
||||||
defaultValue={defaultCryptoId}
|
|
||||||
onValueChange={(val) => {
|
|
||||||
const maxShares = getMaxSharesForCrypto(val);
|
|
||||||
setSliderValue(maxShares);
|
|
||||||
setQuantity(1);
|
|
||||||
setSelectedCrypto(val);
|
|
||||||
field.onChange(val);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FormControl>
|
|
||||||
<SelectTrigger>
|
|
||||||
<SelectValue placeholder="Select a crypto from your wallet." />
|
|
||||||
</SelectTrigger>
|
|
||||||
</FormControl>
|
|
||||||
<SelectContent>
|
|
||||||
{currentWallet?.map((crypto) => (<SelectItem value={crypto.Crypto.id} key={crypto.Crypto.id}>
|
|
||||||
{`${crypto.amount}x ${crypto.Crypto.name} - ${Math.round(crypto.Crypto.value)}$/u`}
|
|
||||||
</SelectItem>))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
|
||||||
control={sellToUserForm.control}
|
|
||||||
name="amount"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem hidden={!selectedCrypto}>
|
|
||||||
<FormLabel>Quantity</FormLabel>
|
|
||||||
<div className="flex items-center justify-between gap-2 p-2">
|
|
||||||
<p className="bg-accent text-accent-foreground p-1 rounded">{field.value}</p>
|
|
||||||
<Slider
|
|
||||||
form="amount"
|
|
||||||
onValueChange={(val) => {
|
|
||||||
const singleValue = val[0];
|
|
||||||
setQuantity(singleValue as number);
|
|
||||||
field.onChange(singleValue);
|
|
||||||
}}
|
|
||||||
value={[quantity]}
|
|
||||||
min={1}
|
|
||||||
max={sliderValue}
|
|
||||||
step={1}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{selectedCrypto && (
|
|
||||||
<div className="flex items-center justify-center p-2 gap-2">
|
|
||||||
<p>{getCryptoName(selectedCrypto)}</p>
|
|
||||||
<X />
|
|
||||||
<p>{quantity}</p>
|
|
||||||
<Equal />
|
|
||||||
<em className="bg-secondary/35 p-1 rounded">
|
|
||||||
{(quantity * getCryptoValue(selectedCrypto)).toLocaleString("en-US")}
|
|
||||||
</em>
|
|
||||||
<DollarSign />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<Button type="submit" disabled={!quantity}>
|
|
||||||
Place sell order
|
|
||||||
</Button>
|
|
||||||
</form>
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
import {Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
|
||||||
import {ScrollArea} from "@/components/ui/scroll-area";
|
|
||||||
import type {IAllTrades} from "@/interfaces/crypto.interface";
|
|
||||||
import {cn} from "@/lib/utils";
|
|
||||||
|
|
||||||
interface OfferListProps {
|
|
||||||
className?: string;
|
|
||||||
trades: IAllTrades;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface RenderRowsProps {
|
|
||||||
data?: IAllTrades;
|
|
||||||
}
|
|
||||||
|
|
||||||
function RenderRows({ data }: RenderRowsProps) {
|
|
||||||
if (!data || data?.length === 0) return (<TableRow>
|
|
||||||
<TableCell className="font-medium">{" "}</TableCell>
|
|
||||||
<TableCell>{" "}</TableCell>
|
|
||||||
<TableCell>{"No history..."}</TableCell>
|
|
||||||
<TableCell className="text-right">{" "}</TableCell>
|
|
||||||
</TableRow>);
|
|
||||||
|
|
||||||
return data.map((item, index) => (
|
|
||||||
<TableRow key={item.Crypto.created_at.toString()}>
|
|
||||||
<TableCell className="font-medium">{item.Giver.pseudo}</TableCell>
|
|
||||||
<TableCell>{item.Receiver.pseudo}</TableCell>
|
|
||||||
<TableCell>{item.Crypto.quantity}</TableCell>
|
|
||||||
<TableCell className="text-right">${item.Crypto.value}</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OfferList({ className, trades}: OfferListProps) {
|
|
||||||
return (<div className={cn("bg-card text-card-foreground rounded p-2", className)}>
|
|
||||||
<Table>
|
|
||||||
<TableCaption>A list of recent sell offers.</TableCaption>
|
|
||||||
<TableHeader>
|
|
||||||
<TableRow>
|
|
||||||
<TableHead className="w-[100px]">Seller</TableHead>
|
|
||||||
<TableHead>Buyer</TableHead>
|
|
||||||
<TableHead>Crypto share amount</TableHead>
|
|
||||||
<TableHead className="text-right">$</TableHead>
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
|
||||||
<RenderRows data={trades}/>
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</div>)
|
|
||||||
}
|
|
@ -15,6 +15,7 @@ export interface IUserData {
|
|||||||
dollarAvailables: number;
|
dollarAvailables: number;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
|
//TODO get on register
|
||||||
wallet: IUserWallet;
|
wallet: IUserWallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user