Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/app/(protected)/crypto/exchange/exchangePlatforms.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const exchangePlatformsGroup = [
{
name: 'Radio button 1',
label: 'Binance',
radioValue: '1',
initialValue: '1',
},
];
4 changes: 3 additions & 1 deletion src/app/(protected)/crypto/exchange/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { Col, Container, Row } from 'react-bootstrap';
import { useTitle } from '@/hooks/useTitle';
import WizardForm from 'module/protect/crypto/exchange/WizardForm';

const CryptoExchanges = () => {
useTitle('Exchanges - BeeQuant');
Expand All @@ -10,9 +11,10 @@ const CryptoExchanges = () => {
<Container>
<Row>
<Col md={12}>
<h3 className="page-title">Crypto Exchanges</h3>
<h3 className="page-title">Connect New Exchange</h3>
</Col>
</Row>
<WizardForm onSubmit={() => {}} />
</Container>
);
};
Expand Down
8 changes: 8 additions & 0 deletions src/graphql/codegen/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ const documents = {
types.GetUserByIdDocument,
'\n mutation updateUser($id: String!, $input: UpdateUserInput!) {\n updateUser(id: $id, input: $input)\n }\n':
types.UpdateUserDocument,
'\n mutation CreateUserExchange($input: CreateUserExchangeInput!) {\n createUserExchange(input: $input) {\n code\n message\n }\n }\n':
types.CreateUserExchangeDocument,
};

/**
Expand Down Expand Up @@ -69,6 +71,12 @@ export function gql(
export function gql(
source: '\n mutation updateUser($id: String!, $input: UpdateUserInput!) {\n updateUser(id: $id, input: $input)\n }\n'
): (typeof documents)['\n mutation updateUser($id: String!, $input: UpdateUserInput!) {\n updateUser(id: $id, input: $input)\n }\n'];
/**
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function gql(
source: '\n mutation CreateUserExchange($input: CreateUserExchangeInput!) {\n createUserExchange(input: $input) {\n code\n message\n }\n }\n'
): (typeof documents)['\n mutation CreateUserExchange($input: CreateUserExchangeInput!) {\n createUserExchange(input: $input) {\n code\n message\n }\n }\n'];

export function gql(source: string) {
return (documents as any)[source] ?? {};
Expand Down
117 changes: 97 additions & 20 deletions src/graphql/codegen/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,28 @@ export type Scalars = {
Float: { input: number; output: number };
/** A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date-time format. */
DateTime: { input: any; output: any };
/** The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */
JSON: { input: any; output: any };
};

export type CreateExchangeKeyInput = {
/** Access key */
/** Input type for creating a user-exchange connection for an exchange account */
export type CreateUserExchangeInput = {
/** Access key for connecting to the exchange */
accessKey: Scalars['String']['input'];
/** Exchange name */
/** Name of the exchange */
exchangeName: Scalars['String']['input'];
/** Remarks */
remarks?: InputMaybe<Scalars['String']['input']>;
/** Secret key */
/** Name of this new user-exchange connection */
name: Scalars['String']['input'];
/** Secret key for connecting to the exchange */
secretKey: Scalars['String']['input'];
};

export type CreateUserExchangeResponse = {
__typename?: 'CreateUserExchangeResponse';
code: Scalars['Int']['output'];
message?: Maybe<Scalars['String']['output']>;
};

export type CreateUserInput = {
/** User display name */
displayName: Scalars['String']['input'];
Expand All @@ -56,25 +65,29 @@ export type ExchangeKey = {
createdBy?: Maybe<Scalars['String']['output']>;
deletedAt?: Maybe<Scalars['DateTime']['output']>;
deletedBy?: Maybe<Scalars['String']['output']>;
/** Exchange name */
exchangeName: Scalars['String']['output'];
id: Scalars['String']['output'];
/** Remarks */
remarks: Scalars['String']['output'];
/** Secret key */
secretKey: Scalars['String']['output'];
updatedAt?: Maybe<Scalars['DateTime']['output']>;
updatedBy?: Maybe<Scalars['String']['output']>;
};

export type ExchangeType = {
__typename?: 'ExchangeType';
/** Exchange ID */
id: Scalars['String']['output'];
/** Exchange name */
name: Scalars['String']['output'];
};

export type Mutation = {
__typename?: 'Mutation';
/** Change password */
changePassword: Result;
/** Create exchange key */
createExchangeKey: Scalars['Boolean']['output'];
/** Create new user */
createUser: Scalars['Boolean']['output'];
/** Create a user exchange connection */
createUserExchange: CreateUserExchangeResponse;
/** Hard delete an user */
deleteUser: Scalars['Boolean']['output'];
/** Hard delete an user key */
Expand All @@ -93,14 +106,14 @@ export type MutationChangePasswordArgs = {
input: UpdatePasswordInput;
};

export type MutationCreateExchangeKeyArgs = {
input: CreateExchangeKeyInput;
};

export type MutationCreateUserArgs = {
input: CreateUserInput;
};

export type MutationCreateUserExchangeArgs = {
input: CreateUserExchangeInput;
};

export type MutationDeleteUserArgs = {
id: Scalars['String']['input'];
};
Expand All @@ -127,10 +140,14 @@ export type Query = {
__typename?: 'Query';
/** Find exchange key by id */
getExchangeKeyById: ExchangeKey;
/** Get all exchanges */
getExchanges: Array<ExchangeType>;
/** Find user by email */
getUserByEmail: UserType;
/** Find user by id */
getUserById: UserType;
/** Get balances for user exchange connections */
getUserExchangeBalances: Array<UserExchangePublic>;
/** Find user by context */
getUserInfo: UserType;
/** Get all users */
Expand Down Expand Up @@ -159,10 +176,6 @@ export type Result = {
export type UpdateExchangeKeyInput = {
/** Access key */
accessKey: Scalars['String']['input'];
/** Exchange name */
exchangeName: Scalars['String']['input'];
/** Remarks */
remarks?: InputMaybe<Scalars['String']['input']>;
/** Secret key */
secretKey: Scalars['String']['input'];
};
Expand All @@ -187,6 +200,14 @@ export type UpdateUserInput = {
ref?: InputMaybe<Scalars['String']['input']>;
};

export type UserExchangePublic = {
__typename?: 'UserExchangePublic';
/** Balance data */
balance?: Maybe<Scalars['JSON']['output']>;
/** The name of the exchange account connection provided by user */
name: Scalars['String']['output'];
};

export type UserType = {
__typename?: 'UserType';
/** User display name */
Expand Down Expand Up @@ -256,6 +277,19 @@ export type UpdateUserMutationVariables = Exact<{

export type UpdateUserMutation = { __typename?: 'Mutation'; updateUser: boolean };

export type CreateUserExchangeMutationVariables = Exact<{
input: CreateUserExchangeInput;
}>;

export type CreateUserExchangeMutation = {
__typename?: 'Mutation';
createUserExchange: {
__typename?: 'CreateUserExchangeResponse';
code: number;
message?: string | null;
};
};

export const LoginDocument = {
kind: 'Document',
definitions: [
Expand Down Expand Up @@ -478,3 +512,46 @@ export const UpdateUserDocument = {
},
],
} as unknown as DocumentNode<UpdateUserMutation, UpdateUserMutationVariables>;
export const CreateUserExchangeDocument = {
kind: 'Document',
definitions: [
{
kind: 'OperationDefinition',
operation: 'mutation',
name: { kind: 'Name', value: 'CreateUserExchange' },
variableDefinitions: [
{
kind: 'VariableDefinition',
variable: { kind: 'Variable', name: { kind: 'Name', value: 'input' } },
type: {
kind: 'NonNullType',
type: { kind: 'NamedType', name: { kind: 'Name', value: 'CreateUserExchangeInput' } },
},
},
],
selectionSet: {
kind: 'SelectionSet',
selections: [
{
kind: 'Field',
name: { kind: 'Name', value: 'createUserExchange' },
arguments: [
{
kind: 'Argument',
name: { kind: 'Name', value: 'input' },
value: { kind: 'Variable', name: { kind: 'Name', value: 'input' } },
},
],
selectionSet: {
kind: 'SelectionSet',
selections: [
{ kind: 'Field', name: { kind: 'Name', value: 'code' } },
{ kind: 'Field', name: { kind: 'Name', value: 'message' } },
],
},
},
],
},
},
],
} as unknown as DocumentNode<CreateUserExchangeMutation, CreateUserExchangeMutationVariables>;
9 changes: 9 additions & 0 deletions src/graphql/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,12 @@ export const UPDATE_USER = gql(`
updateUser(id: $id, input: $input)
}
`);

export const CREATE_USER_EXCHANGE = gql(`
mutation CreateUserExchange($input: CreateUserExchangeInput!) {
createUserExchange(input: $input) {
code
message
}
}
`);
43 changes: 43 additions & 0 deletions src/module/protect/crypto/exchange/StepOne.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// StepOne.test.js

import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom';
import StepOne from './StepOne';
import { exchangePlatformsGroup } from '../../../../app/(protected)/crypto/exchange/exchangePlatforms';
// Mock props
const defaultValues = {};
const onSubmit = jest.fn();

describe('StepOne Component', () => {
beforeEach(() => {
render(<StepOne onSubmit={onSubmit} defaultValues={defaultValues} />);
onSubmit.mockClear();
});

test('renders StepOne correctly', () => {
expect(screen.getByText('Select your exchange')).toBeInTheDocument();
exchangePlatformsGroup.forEach((item) => {
expect(screen.getByLabelText(item.label)).toBeInTheDocument();
});
expect(screen.getByRole('button', { name: /Next/i })).toBeInTheDocument();
});

test('submits the form with selected exchange', async () => {
fireEvent.click(screen.getByLabelText('Binance'));

const radioButton = screen.getByLabelText('Binance') as HTMLInputElement;
console.log('Radio button checked state:', radioButton.checked);
expect(radioButton).toBeChecked();

await fireEvent.click(await screen.findByRole('button', { name: /Next/i }));

expect(onSubmit).toHaveBeenCalledWith({ exchange: '1' });
});

test('does not submit the form without selecting exchange', () => {
fireEvent.click(screen.getByRole('button', { name: /Next/i }));

expect(onSubmit).not.toHaveBeenCalled();
});
});
79 changes: 79 additions & 0 deletions src/module/protect/crypto/exchange/StepOne.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
'use client';

import React, { useState, useEffect } from 'react';
import { FormGroup, FormGroupField } from '@/shared/components/form/FormElements';
import styled from 'styled-components';
import {
WizardButtonToolbar,
WizardFormContainer,
WizardTitle,
StyledButton,
WizardLabel,
} from '@/shared/components/form/WizardFormElements';
import { exchangePlatformsGroup } from '../../../../app/(protected)/crypto/exchange/exchangePlatforms';

interface StepOneProps {
onSubmit: (data: any) => void;
defaultValues: Record<string, any>;
}

const StepOne: React.FC<StepOneProps> = ({ onSubmit, defaultValues }) => {
const [formData, setFormData] = useState(defaultValues);

useEffect(() => {
setFormData(defaultValues);
}, [defaultValues]);

const handlePlatformSelect = (platform: string) => {
setFormData((prevData) => ({
...prevData,
exchange: platform,
}));
};

const handleNext = (e: React.FormEvent) => {
e.preventDefault();
if (!formData.exchange) {
return;
}
onSubmit(formData);
};

return (
<>
<WizardFormContainer onSubmit={handleNext}>
<WizardTitle>Select your exchange</WizardTitle>
<FormGroup>
<div>
{exchangePlatformsGroup.map((item) => (
<FormGroupField key={`index_${item.label}`}>
<WizardLabel>
<Input
type="radio"
value={item.radioValue}
checked={formData.exchange === item.radioValue}
onChange={() => handlePlatformSelect(item.radioValue)}
/>
{item.label}
</WizardLabel>
</FormGroupField>
))}
</div>
</FormGroup>
<WizardButtonToolbar>
<StyledButton type="submit" className="next">
Next
</StyledButton>
</WizardButtonToolbar>
</WizardFormContainer>
</>
);
};

export default StepOne;

const Input = styled.input`
margin-right: 10px;
width: 20px;
height: 20px;
`;
Loading