Skip to content

Commit

Permalink
Merge branch 'deriv-com:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmed-deriv authored Jan 14, 2025
2 parents deba671 + 44df3f5 commit bb59903
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 64 deletions.
1 change: 0 additions & 1 deletion src/components/TradingComponents/Chart/Chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ export const Chart = observer(() => {
} = chartStore;
const derivAPI = getDerivAPI();
const [isConnected, setIsConnected] = useState(derivAPI.isConnected());

// Initialize chart store
useEffect(() => {
setSymbol("1HZ10V");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export const DurationSection = ({
message={durationError}
/>
<Text as="span" size="sm" className="text-less-prominent">
Range: 1 - 1,440 minutes
Range: 15 - 1,440 minutes
</Text>
</div>
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,13 @@
.equals-section {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 0;
gap: 0.5rem;
margin-bottom: 1rem;
}

.error-message {
margin: 1rem;
text-align: center;
}

.payout-section {
Expand Down
115 changes: 64 additions & 51 deletions src/components/TradingComponents/TradingPanel/TradingPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { Button, Text, Tooltip, Checkbox } from "@deriv-com/quill-ui";
import { Button, Text } from "@deriv-com/quill-ui";
import {
LabelPairedBackwardSmBoldIcon,
TradeTypesUpsAndDownsRiseIcon,
TradeTypesUpsAndDownsFallIcon,
LabelPairedCircleInfoSmBoldIcon,
} from "@deriv/quill-icons";
import { observer } from "mobx-react-lite";
import { tradingPanelStore } from "../../../stores/TradingPanelStore";
import { chartStore } from "../../../stores/ChartStore";
import { usePriceProposal } from "../../../hooks/usePriceProposal";
import { useRiseFallTrading } from "../../../hooks/useRiseFallTrading";
import { DurationSection } from "../DurationSection/DurationSection";
import { StakeSection } from "../StakeSection/StakeSection";
import { TradeButton } from "../TradeButton/TradeButton";
Expand All @@ -29,15 +28,17 @@ export const TradingPanel = observer(() => {
setSelectedStakeTab,
durationError,
priceError,
is_rise_fall_valid,
} = tradingPanelStore;

const { proposal, clearProposal, isLoading } = usePriceProposal(
const { proposal, clearProposal, isLoading } = useRiseFallTrading(
chartStore.symbol,
price,
duration,
selectedStakeTab,
chartStore.symbol,
durationError,
priceError
priceError,
is_rise_fall_valid
);

const getAmount = (type: "rise" | "fall"): string => {
Expand Down Expand Up @@ -88,54 +89,66 @@ export const TradingPanel = observer(() => {
</div>
</div>

<div className="tabs-container">
<DurationSection
duration={duration}
selectedDurationTab={selectedDurationTab}
durationError={durationError ?? ""}
setDuration={setDuration}
setSelectedDurationTab={setSelectedDurationTab}
/>
<StakeSection
price={price}
selectedStakeTab={selectedStakeTab}
priceError={priceError ?? ""}
setPrice={setPrice}
setSelectedStakeTab={setSelectedStakeTab}
/>
</div>
{!is_rise_fall_valid ? (
<div className="error-message">
<Text as="p" size="sm" color="error">
This contract type is not valid for Rise/Fall
</Text>
</div>
) : (
<>
<div className="tabs-container">
<DurationSection
duration={duration}
selectedDurationTab={selectedDurationTab}
durationError={durationError ?? ""}
setDuration={setDuration}
setSelectedDurationTab={setSelectedDurationTab}
/>
<StakeSection
price={price}
selectedStakeTab={selectedStakeTab}
priceError={priceError ?? ""}
setPrice={setPrice}
setSelectedStakeTab={setSelectedStakeTab}
/>
</div>

<div className="equals-section">
<Checkbox
name="allow-equals"
checked={allowEquals}
onChange={(e) =>
setAllowEquals((e.target as HTMLInputElement).checked)
}
label="Allow equals"
/>
<Tooltip tooltipContent="Allow equals tooltip">
<LabelPairedCircleInfoSmBoldIcon className="text-less-prominent" />
</Tooltip>
</div>
{/* Equals section temporarily hidden
<div className="equals-section">
<Checkbox
name="allow-equals"
checked={allowEquals}
onChange={(e) =>
setAllowEquals((e.target as HTMLInputElement).checked)
}
label="Allow equals"
/>
<Tooltip tooltipContent="Allow equals tooltip">
<LabelPairedCircleInfoSmBoldIcon className="text-less-prominent" />
</Tooltip>
</div>
*/}

<div className="payout-section">
<TradeButton type="rise" percentage={getPercentage("rise")} />
<PayoutInfo
type="rise"
label={label}
amount={getAmount("rise")}
isLoading={isLoading.rise}
/>
<div className="payout-section">
<TradeButton type="rise" percentage={getPercentage("rise")} />
<PayoutInfo
type="rise"
label={label}
amount={getAmount("rise")}
isLoading={isLoading.rise}
/>

<TradeButton type="fall" percentage={getPercentage("fall")} />
<PayoutInfo
type="fall"
label={label}
amount={getAmount("fall")}
isLoading={isLoading.fall}
/>
</div>
<TradeButton type="fall" percentage={getPercentage("fall")} />
<PayoutInfo
type="fall"
label={label}
amount={getAmount("fall")}
isLoading={isLoading.fall}
/>
</div>
</>
)}
</div>
);
});
32 changes: 32 additions & 0 deletions src/hooks/useContractsFor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useEffect } from "react";
import { getDerivAPI } from "../services/deriv-api.instance";
import { tradingPanelStore } from "../stores/TradingPanelStore";

export const useContractsFor = (symbol: string) => {
const derivAPI = getDerivAPI();

useEffect(() => {
const checkContractsAvailability = async () => {
if (!symbol) return;

try {
const contractsResponse = await derivAPI.getContractsForSymbol(symbol);

const hasRiseFallContracts =
contractsResponse.contracts_for.available.some(
(contract) =>
contract.contract_category === "callput" &&
contract.barriers === 0 &&
contract.barrier_category === "euro_atm"
);

tradingPanelStore.setIsRiseFallValid(hasRiseFallContracts);
} catch (error) {
console.error("Error fetching contracts:", error);
tradingPanelStore.setIsRiseFallValid(false);
}
};

checkContractsAvailability();
}, [symbol, derivAPI]);
};
28 changes: 22 additions & 6 deletions src/hooks/usePriceProposal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useEffect, useState } from "react";
import { getDerivAPI } from "../services/deriv-api.instance";
import { PriceProposalResponse } from "../types/deriv-api.types";
import useDebounce from "./useDebounce";
import { tradingPanelStore } from "../stores/TradingPanelStore";

interface ProposalState {
rise?: PriceProposalResponse["proposal"];
Expand All @@ -18,8 +19,9 @@ export const usePriceProposal = (
duration: number,
basis: string,
symbol: string,
durationError: string,
priceError: string
durationError: string | null,
priceError: string | null,
is_rise_fall_valid: boolean
) => {
const [proposal, setProposal] = useState<ProposalState>({});
const [isLoading, setIsLoading] = useState<LoadingState>({
Expand Down Expand Up @@ -71,15 +73,22 @@ export const usePriceProposal = (
setIsLoading((prev) => ({ ...prev, [type]: false }));
if (response.error) {
console.error(`${type} proposal error:`, response.error);
tradingPanelStore.priceError =
response.error.message || "Invalid contract parameters";
} else if (response.proposal) {
setProposal((prev) => ({ ...prev, [type]: response.proposal }));
}
},
`PROPOSAL_${type.toUpperCase()}`
);
} catch (err) {
} catch (err: any) {
console.error(`${type} subscription error:`, err);
setIsLoading((prev) => ({ ...prev, [type]: false }));

if (err.code === "ContractBuyValidationError") {
tradingPanelStore.priceError =
err.message || "Invalid contract parameters";
}
}
};

Expand All @@ -91,18 +100,25 @@ export const usePriceProposal = (

setProposal({});
setIsLoading({ rise: false, fall: false });

if (
debouncedPrice &&
duration &&
basis &&
symbol &&
!durationError &&
!priceError
!priceError &&
is_rise_fall_valid
) {
handleProposal();
}
}, [debouncedPrice, debouncedDuration, basis, symbol, derivAPI]);
}, [
debouncedPrice,
debouncedDuration,
basis,
symbol,
derivAPI,
is_rise_fall_valid,
]);

return { proposal, clearProposal, isLoading };
};
30 changes: 30 additions & 0 deletions src/hooks/useRiseFallTrading.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { useContractsFor } from "./useContractsFor";
import { usePriceProposal } from "./usePriceProposal";

export const useRiseFallTrading = (
symbol: string,
price: string,
duration: number,
basis: string,
durationError: string | null,
priceError: string | null,
isRiseFallValid: boolean
) => {
// Use both hooks internally
useContractsFor(symbol);
const { proposal, clearProposal, isLoading } = usePriceProposal(
price,
duration,
basis,
symbol,
durationError,
priceError,
isRiseFallValid
);

return {
proposal,
clearProposal,
isLoading,
};
};
4 changes: 4 additions & 0 deletions src/stores/ChartStore.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { makeAutoObservable } from "mobx";
import { tradingPanelStore } from "./TradingPanelStore";

export class ChartStore {
symbol: string = "";
Expand All @@ -10,7 +11,10 @@ export class ChartStore {
}

setSymbol = (symbol: string) => {
tradingPanelStore.setIsRiseFallValid(false);
this.symbol = symbol;
tradingPanelStore.priceError = null;
tradingPanelStore.durationError = null;
};

setChartStatus = (status: boolean) => {
Expand Down
11 changes: 8 additions & 3 deletions src/stores/TradingPanelStore.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { makeAutoObservable } from "mobx";

export class TradingPanelStore {
duration = 1;
duration = 15;
price = "10";
allowEquals = false;
selectedDurationTab: "duration" | "endtime" = "duration";
selectedStakeTab: "stake" | "payout" = "stake";
durationError: string | null = null;
priceError: string | null = null;
is_rise_fall_valid: boolean = true;

constructor() {
makeAutoObservable(this);
Expand All @@ -26,8 +27,8 @@ export class TradingPanelStore {
return;
}

if (numValue <= 0) {
this.durationError = "Duration must be greater than 0";
if (numValue < 15) {
this.durationError = "Minimum duration is 15 minutes";
return;
}

Expand Down Expand Up @@ -73,6 +74,10 @@ export class TradingPanelStore {
setSelectedStakeTab = (value: "stake" | "payout") => {
this.selectedStakeTab = value;
};

setIsRiseFallValid = (value: boolean) => {
this.is_rise_fall_valid = value;
};
}

export const tradingPanelStore = new TradingPanelStore();

0 comments on commit bb59903

Please sign in to comment.