Skip to content
This repository was archived by the owner on Jul 15, 2025. It is now read-only.

Commit 4d32cda

Browse files
authored
Merge pull request #58 from deriv-com/farabi/fix-landscape-view-issues
Farabi/fix landscape view issues
2 parents 9748c1e + 6045cb4 commit 4d32cda

File tree

14 files changed

+60
-65
lines changed

14 files changed

+60
-65
lines changed

src/components/BottomSheet/BottomSheet.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { useRef, useCallback, useEffect } from "react";
22
import { useBottomSheetStore } from "@/stores/bottomSheetStore";
33
import { bottomSheetConfig } from "@/config/bottomSheetConfig";
4-
import { useDeviceDetection } from "@/hooks/useDeviceDetection";
54
import { PrimaryButton } from "../ui/primary-button";
5+
import { useOrientationStore } from "@/stores/orientationStore";
66

77
export const BottomSheet = () => {
88
const {
@@ -13,7 +13,7 @@ export const BottomSheet = () => {
1313
actionButton,
1414
setBottomSheet,
1515
} = useBottomSheetStore();
16-
const { isDesktop } = useDeviceDetection();
16+
const { isLandscape } = useOrientationStore();
1717

1818
const sheetRef = useRef<HTMLDivElement>(null);
1919
const dragStartY = useRef<number>(0);
@@ -162,7 +162,7 @@ export const BottomSheet = () => {
162162
onTouchStart={handleTouchStart}
163163
onMouseDown={handleMouseDown}
164164
onClick={() => {
165-
if (isDesktop) {
165+
if (isLandscape) {
166166
onDragDown?.();
167167
setBottomSheet(false);
168168
}

src/components/BottomSheet/__tests__/BottomSheet.test.tsx

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -155,27 +155,6 @@ describe("BottomSheet", () => {
155155
expect(mockSetBottomSheet).toHaveBeenCalledWith(false);
156156
});
157157

158-
it("closes bottom sheet when clicking handle bar on desktop", () => {
159-
mockUseDeviceDetection.mockReturnValue({ isDesktop: true });
160-
const mockOnDragDown = jest.fn();
161-
mockUseBottomSheetStore.mockReturnValue({
162-
showBottomSheet: true,
163-
key: 'test-key',
164-
height: '380px',
165-
onDragDown: mockOnDragDown,
166-
setBottomSheet: mockSetBottomSheet
167-
});
168-
169-
const { container } = render(<BottomSheet />);
170-
171-
const handleBar = container.querySelector('[class*="flex flex-col items-center"]');
172-
expect(handleBar).toBeInTheDocument();
173-
fireEvent.click(handleBar!);
174-
175-
expect(mockOnDragDown).toHaveBeenCalled();
176-
expect(mockSetBottomSheet).toHaveBeenCalledWith(false);
177-
});
178-
179158
it("does not close bottom sheet when clicking handle bar on mobile", () => {
180159
mockUseDeviceDetection.mockReturnValue({ isDesktop: false });
181160
mockUseBottomSheetStore.mockReturnValue({

src/components/Duration/DurationController.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import { BottomSheetHeader } from "@/components/ui/bottom-sheet-header";
44
import { DurationValueList } from "./components/DurationValueList";
55
import { HoursDurationValue } from "./components/HoursDurationValue";
66
import { useTradeStore } from "@/stores/tradeStore";
7-
import { useDeviceDetection } from "@/hooks/useDeviceDetection";
87
import { PrimaryButton } from "@/components/ui/primary-button";
98
import { generateDurationValues as getDurationValues } from "@/utils/duration";
109
import { useBottomSheetStore } from "@/stores/bottomSheetStore";
1110
import { useDebounce } from "@/hooks/useDebounce";
1211
import { DesktopTradeFieldCard } from "@/components/ui/desktop-trade-field-card";
1312
import type { DurationRangesResponse } from "@/services/api/rest/duration/types";
13+
import { useOrientationStore } from "@/stores/orientationStore";
1414

1515
const DURATION_TYPES: Tab[] = [
1616
{ label: "Ticks", value: "tick" },
@@ -30,7 +30,7 @@ export const DurationController: React.FC<DurationControllerProps> = ({
3030
onClose,
3131
}) => {
3232
const { duration, setDuration } = useTradeStore();
33-
const { isDesktop } = useDeviceDetection();
33+
const { isLandscape } = useOrientationStore();
3434
const { setBottomSheet } = useBottomSheetStore();
3535
const isInitialRender = useRef(true);
3636

@@ -52,7 +52,7 @@ export const DurationController: React.FC<DurationControllerProps> = ({
5252
useDebounce(
5353
localDuration,
5454
(value) => {
55-
if (isDesktop) {
55+
if (isLandscape) {
5656
setDuration(value);
5757
}
5858
},
@@ -74,14 +74,14 @@ export const DurationController: React.FC<DurationControllerProps> = ({
7474
const newDuration = `${value} ${selectedType}`;
7575
setLocalDuration(newDuration);
7676
setDuration(newDuration); // Update store immediately on click
77-
if (isDesktop) {
77+
if (isLandscape) {
7878
onClose?.();
7979
}
8080
};
8181

8282
const handleSave = () => {
8383
setDuration(localDuration);
84-
if (isDesktop) {
84+
if (isLandscape) {
8585
onClose?.();
8686
} else {
8787
setBottomSheet(false);
@@ -90,15 +90,15 @@ export const DurationController: React.FC<DurationControllerProps> = ({
9090

9191
const content = (
9292
<>
93-
<div className={isDesktop ? "flex" : ""}>
94-
{!isDesktop && <BottomSheetHeader title="Duration" />}
93+
<div className={isLandscape ? "flex" : ""}>
94+
{!isLandscape && <BottomSheetHeader title="Duration" />}
9595
<TabList
9696
tabs={DURATION_TYPES}
9797
selectedValue={selectedType}
9898
onSelect={handleTypeSelect as (value: string) => void}
99-
variant={isDesktop ? "vertical" : "chip"}
99+
variant={isLandscape ? "vertical" : "chip"}
100100
/>
101-
<div className={`flex-1 relative bg-white ${isDesktop ? "px-2" : "px-8"}`}>
101+
<div className={`flex-1 relative bg-white ${isLandscape ? "px-2" : "px-8"}`}>
102102
{selectedType === "hour" ? (
103103
<HoursDurationValue
104104
selectedValue={selectedValue.toString()}
@@ -120,7 +120,7 @@ export const DurationController: React.FC<DurationControllerProps> = ({
120120
)}
121121
</div>
122122
</div>
123-
{!isDesktop && (
123+
{!isLandscape && (
124124
<div className="w-full p-3">
125125
<PrimaryButton className="rounded-3xl" onClick={handleSave}>
126126
Save
@@ -130,7 +130,7 @@ export const DurationController: React.FC<DurationControllerProps> = ({
130130
</>
131131
);
132132

133-
if (isDesktop) {
133+
if (isLandscape) {
134134
return (
135135
<DesktopTradeFieldCard className="p-0">
136136
<div className="w-[368px]">{content}</div>

src/components/Duration/DurationField.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import React, { useState, useRef } from "react"
22
import { useTradeStore } from "@/stores/tradeStore"
33
import { useBottomSheetStore } from "@/stores/bottomSheetStore"
4-
import { useDeviceDetection } from "@/hooks/useDeviceDetection"
54
import TradeParam from "@/components/TradeFields/TradeParam"
65
import { DurationController } from "./DurationController"
76
import { Popover } from "@/components/ui/popover"
87
import { DesktopTradeFieldCard } from "@/components/ui/desktop-trade-field-card"
8+
import { useOrientationStore } from "@/stores/orientationStore"
99

1010
interface DurationFieldProps {
1111
className?: string
@@ -14,12 +14,12 @@ interface DurationFieldProps {
1414
export const DurationField: React.FC<DurationFieldProps> = ({ className }) => {
1515
const { duration } = useTradeStore()
1616
const { setBottomSheet } = useBottomSheetStore()
17-
const { isDesktop } = useDeviceDetection()
17+
const { isLandscape } = useOrientationStore()
1818
const [isOpen, setIsOpen] = useState(false)
1919
const popoverRef = useRef<{ isClosing: boolean }>({ isClosing: false })
2020

2121
const handleClick = () => {
22-
if (isDesktop) {
22+
if (isLandscape) {
2323
if (!popoverRef.current.isClosing) {
2424
setIsOpen(!isOpen)
2525
}
@@ -39,7 +39,7 @@ export const DurationField: React.FC<DurationFieldProps> = ({ className }) => {
3939

4040
return (
4141
<div className="relative">
42-
{isDesktop ? (
42+
{isLandscape ? (
4343
<DesktopTradeFieldCard isSelected={isOpen}>
4444
<TradeParam
4545
label="Duration"
@@ -56,7 +56,7 @@ export const DurationField: React.FC<DurationFieldProps> = ({ className }) => {
5656
className={className}
5757
/>
5858
)}
59-
{isDesktop && isOpen && (
59+
{isLandscape && isOpen && (
6060
<Popover
6161
isOpen={isOpen}
6262
onClose={handleClose}

src/components/HowToTrade/HowToTrade.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export const HowToTrade: React.FC = () => {
1313
if (isDesktop) {
1414
setIsModalOpen(true);
1515
} else {
16-
setBottomSheet(true, "how-to-trade", "90%", {
16+
setBottomSheet(true, "how-to-trade", "80%", {
1717
show: true,
1818
label: "Got it",
1919
onClick: () => setBottomSheet(false)

src/components/HowToTrade/__tests__/HowToTrade.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ describe('HowToTrade', () => {
2727
const call = mockSetBottomSheet.mock.calls[0];
2828
expect(call[0]).toBe(true);
2929
expect(call[1]).toBe('how-to-trade');
30-
expect(call[2]).toBe('90%');
30+
expect(call[2]).toBe('80%');
3131
expect(call[3]).toEqual(expect.objectContaining({
3232
show: true,
3333
label: "Got it",

src/components/SideNav/SideNav.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ export const SideNav: React.FC<{ setMenuOpen: (open: boolean) => void; isMenuOpe
1010
const location = useLocation();
1111
const { isLoggedIn } = useClientStore();
1212
const { isLandscape } = useOrientationStore();
13-
const { isSidebarOpen, setSidebarOpen } = useMainLayoutStore();
13+
const { isSidebarOpen, setSidebarOpen, isSideNavVisible } = useMainLayoutStore();
1414

1515
return (
16-
<nav className={`${isLandscape ? 'flex' : 'hidden'} fixed z-[100] flex-col h-[100dvh] sticky top-0 w-16 border-r bg-white overflow-y-auto`}>
16+
<nav className={`${isLandscape && isSideNavVisible ? 'flex' : 'hidden'} fixed z-[60] flex-col h-[100dvh] sticky top-0 w-16 border-r bg-white overflow-y-auto`}>
1717
<div className="flex flex-col items-center gap-6 py-6">
1818
{isLoggedIn && (
1919
<>

src/components/Stake/StakeController.tsx

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@ import React, { useEffect, useState } from "react";
22
import { useTradeStore } from "@/stores/tradeStore";
33
import { useClientStore } from "@/stores/clientStore";
44
import { BottomSheetHeader } from "@/components/ui/bottom-sheet-header";
5-
import { useDeviceDetection } from "@/hooks/useDeviceDetection";
65
import { useBottomSheetStore } from "@/stores/bottomSheetStore";
76
import { useDebounce } from "@/hooks/useDebounce";
87
import { StakeInputLayout } from "./components/StakeInputLayout";
98
import { PrimaryButton } from "@/components/ui/primary-button";
109
import { parseStakeAmount, STAKE_CONFIG } from "@/config/stake";
11-
import { DesktopTradeFieldCard } from "@/components/ui/desktop-trade-field-card";
1210
import { validateStake } from "./utils/validation";
1311
import { parseDuration, formatDuration } from "@/utils/duration";
1412
import { createSSEConnection } from "@/services/api/sse/createSSEConnection";
1513
import { tradeTypeConfigs } from "@/config/tradeTypes";
14+
import { useOrientationStore } from "@/stores/orientationStore";
1615

1716
interface ButtonState {
1817
loading: boolean;
@@ -28,7 +27,7 @@ interface StakeControllerProps {}
2827
export const StakeController: React.FC<StakeControllerProps> = () => {
2928
const { stake, setStake, trade_type, duration, payouts, setPayouts } = useTradeStore();
3029
const { currency, token } = useClientStore();
31-
const { isDesktop } = useDeviceDetection();
30+
const { isLandscape } = useOrientationStore();
3231
const { setBottomSheet } = useBottomSheetStore();
3332

3433
const [localStake, setLocalStake] = React.useState(stake);
@@ -184,7 +183,7 @@ export const StakeController: React.FC<StakeControllerProps> = () => {
184183
const handleStakeChange = (value: string) => {
185184
if (preventExceedingMax(value)) return;
186185

187-
if (isDesktop) {
186+
if (isLandscape) {
188187
setLocalStake(value);
189188
validateStakeOnly(value);
190189
return;
@@ -195,18 +194,18 @@ export const StakeController: React.FC<StakeControllerProps> = () => {
195194
};
196195

197196
useEffect(() => {
198-
if (!isDesktop) return;
197+
if (!isLandscape) return;
199198

200199
if (debouncedStake !== stake) {
201200
const validation = validateStakeOnly(debouncedStake);
202201
if (!validation.error) {
203202
setStake(debouncedStake);
204203
}
205204
}
206-
}, [isDesktop, debouncedStake, stake]);
205+
}, [isLandscape, debouncedStake, stake]);
207206

208207
const handleSave = () => {
209-
if (isDesktop) return;
208+
if (isLandscape) return;
210209

211210
const validation = validateAndUpdateStake(localStake);
212211
if (validation.error) return;
@@ -217,7 +216,7 @@ export const StakeController: React.FC<StakeControllerProps> = () => {
217216

218217
const content = (
219218
<>
220-
{!isDesktop && <BottomSheetHeader title="Stake" />}
219+
{!isLandscape && <BottomSheetHeader title="Stake" />}
221220
<div className="flex flex-col justify-between flex-grow px-6">
222221
<StakeInputLayout
223222
value={localStake}
@@ -226,15 +225,15 @@ export const StakeController: React.FC<StakeControllerProps> = () => {
226225
errorMessage={errorMessage}
227226
maxPayout={payouts.max}
228227
payoutValues={payouts.values}
229-
isDesktop={isDesktop}
228+
isDesktop={isLandscape}
230229
loading={Object.values(buttonStates).some(state => state.loading)}
231230
loadingStates={Object.keys(buttonStates).reduce((acc, key) => ({
232231
...acc,
233232
[key]: buttonStates[key].loading
234233
}), {})}
235234
/>
236235
</div>
237-
{!isDesktop && (
236+
{!isLandscape && (
238237
<div className="w-full py-6 px-3">
239238
<PrimaryButton
240239
className="rounded-3xl"
@@ -248,7 +247,7 @@ export const StakeController: React.FC<StakeControllerProps> = () => {
248247
</>
249248
);
250249

251-
if (isDesktop) {
250+
if (isLandscape) {
252251
return (
253252
<div className="w-[480px]">{content}</div>
254253
);

src/components/Stake/StakeField.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import React from "react"
2-
import { useDeviceDetection } from "@/hooks/useDeviceDetection"
32
import TradeParam from "@/components/TradeFields/TradeParam"
43
import { Tooltip } from "@/components/ui/tooltip"
54
import { useStakeField } from "./hooks/useStakeField"
65
import { cn } from "@/lib/utils"
6+
import { useOrientationStore } from "@/stores/orientationStore"
77

88
interface StakeFieldProps {
99
className?: string
@@ -16,7 +16,7 @@ export const StakeField: React.FC<StakeFieldProps> = ({
1616
onSelect,
1717
onError,
1818
}) => {
19-
const { isDesktop } = useDeviceDetection()
19+
const { isLandscape } = useOrientationStore()
2020
const {
2121
stake,
2222
currency,
@@ -32,7 +32,7 @@ export const StakeField: React.FC<StakeFieldProps> = ({
3232
handleMobileClick,
3333
} = useStakeField({ onSelect, onError })
3434

35-
if (!isDesktop) {
35+
if (!isLandscape) {
3636
return (
3737
<div className="flex flex-col">
3838
<div

src/components/TradeFields/TradeParamField.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useState, useRef } from "react";
2-
import { useDeviceDetection } from "@/hooks/useDeviceDetection";
32
import TradeParam from "./TradeParam";
3+
import { useOrientationStore } from "@/stores/orientationStore";
44

55
interface TradeParamFieldProps {
66
label: string;
@@ -17,12 +17,12 @@ export const TradeParamField: React.FC<TradeParamFieldProps> = ({
1717
onSelect,
1818
className,
1919
}) => {
20-
const { isDesktop } = useDeviceDetection();
20+
const { isLandscape } = useOrientationStore();
2121
const [showPopover, setShowPopover] = useState(false);
2222
const paramRef = useRef<HTMLDivElement>(null);
2323

2424
const handleClick = () => {
25-
if (isDesktop) {
25+
if (isLandscape) {
2626
setShowPopover(true);
2727
} else {
2828
onSelect?.();
@@ -62,7 +62,7 @@ export const TradeParamField: React.FC<TradeParamFieldProps> = ({
6262
className={className}
6363
/>
6464

65-
{isDesktop && showPopover && (
65+
{isLandscape && showPopover && (
6666
<>
6767
{/* Popover */}
6868
<div

0 commit comments

Comments
 (0)