Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/tracking tool panel #983

Merged
merged 6 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "baifa",
"version": "0.1.1+31",
"version": "0.1.1+32",
"scripts": {
"dev": "next dev",
"build": "next build",
Expand Down
File renamed without changes
File renamed without changes
160 changes: 160 additions & 0 deletions src/components/add_address_panel/add_address_panel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import {IoIosCloseCircleOutline} from 'react-icons/io';
import {HiPlus} from 'react-icons/hi';
import {FaHeart} from 'react-icons/fa';
import {FiTrash2} from 'react-icons/fi';
import {useState} from 'react';
import useAPIResponse from '../../lib/hooks/use_api_response';
import {HttpMethod} from '../../constants/api_request';
import {buttonStyle} from '../../constants/config';

interface IAddAddressPanelProps {
modalVisible: boolean;
modalClickHandler: () => void;
addAddressHandler: (address: string) => void;
}

const AddAddressPanel = ({
modalVisible,
modalClickHandler,
addAddressHandler,
}: IAddAddressPanelProps) => {
// Info: (20240326 - Julian) 是否顯示 Following List
const [visibleFollowingList, setVisibleFollowingList] = useState(false);
// Info: (20240326 - Julian) address 清單
// ToDo: (20240326 - Julian) 之後應該要改成 <string[]>
const [preAddAddressList, setPreAddAddressList] = useState<string>('');

const {data: followingList, isLoading: isFollowingList} = useAPIResponse<string[]>(
'/api/v1/app/tracking_tool/add_address_list',
{method: HttpMethod.GET}
);

const visibleFollowingListHandler = () => setVisibleFollowingList(prev => !prev);

// Info: (20240326 - Julian) 點擊 Add 按鈕後的處理
const addAddressButtonHandler = () => {
addAddressHandler(preAddAddressList);
modalClickHandler();
};
// Info: (20240326 - Julian) 如果清單為空,就不能點擊 Add 按鈕
const addAddressButtonDisabled = preAddAddressList === '';

//
const displayPreAddAddressList =
preAddAddressList !== '' ? (
<div className="flex w-full items-center border-b border-darkPurple4 px-4 py-2">
<p className="w-100px grow overflow-hidden text-ellipsis whitespace-nowrap text-left text-xl font-semibold text-primaryBlue lg:w-300px">
<span className="text-hoverWhite">Address </span>
{preAddAddressList}
</p>

{/* Info: (20240326 - Julian) Delete button */}
<button onClick={() => setPreAddAddressList('')} className={`${buttonStyle} ml-4`}>
<FiTrash2 size={24} />
</button>
</div>
) : null;

const displayFollowingList =
!isFollowingList && followingList ? (
followingList.map((address, index) => {
// Info: (20240326 - Julian) 將地址加入清單並關閉 Following List
const addButtonHandler = () => {
setPreAddAddressList(address);
visibleFollowingListHandler();
};
return (
<div
key={index}
className="flex w-full items-center border-b border-darkPurple4 px-4 py-2"
>
<p className="w-100px grow overflow-hidden text-ellipsis whitespace-nowrap text-left text-xl font-semibold text-primaryBlue lg:w-300px">
<span className="text-hoverWhite">Address </span>
{address}
</p>

{/* Info: (20240326 - Julian) Add button */}
<button onClick={addButtonHandler} className={`${buttonStyle} ml-4`}>
<HiPlus size={24} />
</button>
</div>
);
})
) : (
<p>Loading...</p>
);

const isShowFollowingList = visibleFollowingList ? (
<div
id="following-list"
className="absolute z-80 flex w-9/10 flex-col items-center rounded bg-darkPurple p-10 shadow-lg lg:w-700px"
>
{/* Info: (20240326 - Julian) Close button */}
<button
onClick={visibleFollowingListHandler}
className="absolute right-6 top-6 hover:opacity-75"
>
<IoIosCloseCircleOutline size={30} />
</button>

<h2 className="text-xl font-semibold">Following List</h2>
{/* Info: (20240326 - Julian) Address list */}
<div className="mt-10 flex h-400px w-full flex-col items-center overflow-y-auto bg-darkPurple3">
{displayFollowingList}
</div>
</div>
) : null;

const isShowPanel = modalVisible ? (
<div className="fixed z-60 flex h-screen w-screen items-center justify-center overflow-hidden bg-black/25 backdrop-blur-sm">
<div
id="add-address-panel"
className="relative z-70 flex h-400px w-9/10 flex-col items-center gap-4 rounded bg-darkPurple p-10 lg:w-700px"
>
{/* Info: (20240326 - Julian) Close button */}
<button onClick={modalClickHandler} className="absolute right-6 top-6 hover:opacity-75">
<IoIosCloseCircleOutline size={30} />
</button>

<h2 className="text-xl font-semibold">Add address</h2>
{/* Info: (20240326 - Julian) Input address */}
<div className="relative flex w-full items-center">
<input
type="text"
placeholder="Enter the address"
className="h-55px w-full rounded bg-purpleLinear px-6 text-base shadow-xl placeholder:text-lilac"
/>
<button
onClick={visibleFollowingListHandler}
className="absolute right-3 rounded bg-violet px-4 py-2 text-sm hover:bg-hoverWhite hover:text-darkPurple3"
>
<p className="hidden lg:block">Following List</p>
<FaHeart size={12} className="block lg:hidden" />
</button>
</div>
{/* Info: (20240326 - Julian) Add button */}
<button className={buttonStyle}>
<HiPlus size={24} />
</button>
{/* Info: (20240326 - Julian) Pre add address list */}
<div className="flex w-full flex-1 flex-col overflow-y-auto">
{displayPreAddAddressList}
</div>

<button
disabled={addAddressButtonDisabled}
onClick={addAddressButtonHandler}
className="rounded bg-primaryBlue px-10 py-4 text-base font-bold text-darkPurple3 hover:bg-hoverWhite hover:text-darkPurple3 disabled:bg-lilac disabled:text-hoverWhite"
>
Add
</button>
</div>
{/* Info: (20240326 - Julian) Following list */}
{isShowFollowingList}
</div>
) : null;

return <>{isShowPanel}</>;
};

export default AddAddressPanel;
4 changes: 1 addition & 3 deletions src/components/pagination/pagination.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Dispatch, SetStateAction, useEffect} from 'react';
import {RiArrowLeftSLine, RiArrowRightSLine} from 'react-icons/ri';
import {DEFAULT_PAGE, ITEM_PER_PAGE} from '../../constants/config';
import {DEFAULT_PAGE, ITEM_PER_PAGE, buttonStyle} from '../../constants/config';
import useStateRef from 'react-usestateref';
import {useRouter} from 'next/router';
import {IAddressHistoryQuery} from '../../constants/api_request';
Expand Down Expand Up @@ -36,8 +36,6 @@ const Pagination = ({
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [targetPage, setTargetPage, targetPageRef] = useStateRef<number>(activePage);

const buttonStyle =
'flex h-48px w-48px items-center justify-center rounded border border-transparent bg-purpleLinear p-3 transition-all duration-300 ease-in-out hover:border-hoverWhite hover:cursor-pointer disabled:opacity-50 disabled:cursor-default disabled:border-transparent';
const router = useRouter();
const {query} = router;

Expand Down
55 changes: 28 additions & 27 deletions src/components/tracking_tool_panel/tracking_tool_panel.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
import Image from 'next/image';
import {useTranslation} from 'next-i18next';
import {useState} from 'react';
import {useState, useContext} from 'react';
import {TrackingContext, TrackingType} from '../../contexts/tracking_context';
import {TranslateFunction} from '../../interfaces/locale';
import {HiPlus, HiMinus} from 'react-icons/hi';
import {FiDownload, FiUpload} from 'react-icons/fi';
import {FaRegBookmark} from 'react-icons/fa';
import {IoIosArrowUp} from 'react-icons/io';

enum TrackingType {
ADDRESS = 'address',
TRANSACTION = 'transaction',
}
import {buttonStyle} from '../../constants/config';
import {truncateText} from '../../lib/common';

const TrackingToolPanel = () => {
const {t}: {t: TranslateFunction} = useTranslation('common');
// Info: (20240325 - Julian) 顯示切換
const [targetTrackingType, setTargetTrackingType] = useState(TrackingType.ADDRESS);
const {targetTrackingType, targetTrackingTypeHandler, visibleAddAddressPanelHandler, addAddress} =
useContext(TrackingContext);

// Info: (20240325 - Julian) 縮放比例
const [zoomPercentage, setZoomPercentage] = useState(100);
// Info: (20240325 - Julian) 工具列展開
const [isToolbarExpanded, setIsToolbarExpanded] = useState(false);

const handleSwitchToAddress = () => setTargetTrackingType(TrackingType.ADDRESS);
const handleSwitchToTransaction = () => setTargetTrackingType(TrackingType.TRANSACTION);

const handleZoomIn = () =>
setZoomPercentage(prev => {
if (prev >= 200) {
Expand Down Expand Up @@ -53,15 +49,15 @@ const TrackingToolPanel = () => {
<div className="flex flex-col items-center gap-4 lg:flex-row">
<p>{t('TRACKING_TOOL_PAGE.VIEW')}</p>
{/* Info: (20240325 - Julian) Input button */}
<button className="flex h-48px w-48px items-center justify-center rounded bg-purpleLinear hover:opacity-75">
<button className={buttonStyle}>
<FiDownload size={24} />
</button>
{/* Info: (20240325 - Julian) Output button */}
<button className="flex h-48px w-48px items-center justify-center rounded bg-purpleLinear hover:opacity-75">
<button className={buttonStyle}>
<FiUpload size={24} />
</button>
{/* Info: (20240325 - Julian) Notes button */}
<button className="flex h-48px w-48px items-center justify-center rounded bg-purpleLinear hover:opacity-75">
<button className={buttonStyle}>
<FaRegBookmark size={24} />
</button>
</div>
Expand All @@ -73,15 +69,15 @@ const TrackingToolPanel = () => {
className={`relative flex w-300px items-center justify-center rounded-full bg-darkPurple px-1 py-1 text-base font-bold ${switchStyle}`}
>
<button
onClick={handleSwitchToAddress}
onClick={targetTrackingTypeHandler}
className={`z-10 rounded-full px-8 py-3 ${
targetTrackingType === TrackingType.ADDRESS ? 'text-hoverWhite' : 'text-lilac'
} transition duration-300 ease-in-out`}
>
{t('TRACKING_TOOL_PAGE.ADDRESS')}
</button>
<button
onClick={handleSwitchToTransaction}
onClick={targetTrackingTypeHandler}
className={`z-10 rounded-full px-8 py-3 ${
targetTrackingType === TrackingType.TRANSACTION ? 'text-hoverWhite' : 'text-lilac'
} transition duration-300 ease-in-out`}
Expand All @@ -95,21 +91,13 @@ const TrackingToolPanel = () => {
const viewZoom = (
<div className="flex items-center space-x-4">
{/* Info: (20240325 - Julian) Plus button */}
<button
onClick={handleZoomIn}
disabled={zoomPercentage >= 200}
className="flex h-48px w-48px items-center justify-center rounded bg-purpleLinear hover:opacity-75 disabled:opacity-50"
>
<button onClick={handleZoomIn} disabled={zoomPercentage >= 200} className={buttonStyle}>
<HiPlus size={24} />
</button>
{/* Info: (20240325 - Julian) Zoom percentage */}
<p className="w-50px text-center text-base">{zoomPercentage} %</p>
{/* Info: (20240325 - Julian) Minus button */}
<button
onClick={handleZoomOut}
disabled={zoomPercentage <= 100}
className="flex h-48px w-48px items-center justify-center rounded bg-purpleLinear hover:opacity-75 disabled:opacity-50"
>
<button onClick={handleZoomOut} disabled={zoomPercentage <= 100} className={buttonStyle}>
<HiMinus size={24} />
</button>
</div>
Expand Down Expand Up @@ -144,7 +132,10 @@ const TrackingToolPanel = () => {
</button>

{/* Info: (20240325 - Julian) Add Address button */}
<button className="group flex w-120px flex-col items-center gap-2">
<button
onClick={visibleAddAddressPanelHandler}
className="group flex w-120px flex-col items-center gap-2"
>
<Image
src="/tracking/add_address.svg"
width={50}
Expand Down Expand Up @@ -218,6 +209,13 @@ const TrackingToolPanel = () => {
</div>
);

const showAddressMap = addAddress ? (
<div className="flex h-100px w-100px flex-col items-center justify-center gap-2 rounded-full border-4 border-primaryBlue">
<Image src="/icons/address_icon.svg" width={24} height={24} alt="address_icon" />
<p className="text-xs">{truncateText(addAddress, 10)}</p>
</div>
) : null;

return (
<div className="relative flex h-full min-h-680px w-full flex-col items-center overflow-hidden border border-darkPurple4 bg-darkPurple5 shadow-inner3xl">
{/* Info: (20240325 - Julian) Tracking Switch */}
Expand All @@ -240,6 +238,9 @@ const TrackingToolPanel = () => {
</button>
{toolbarList}
</div>

{/* Info: (20240325 - Julian) Tracking View */}
<div className="mx-auto my-auto">{showAddressMap}</div>
</div>
);
};
Expand Down
3 changes: 3 additions & 0 deletions src/constants/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,9 @@ export const THRESHOLD_FOR_BLOCK_STABILITY = {
LOW: 10,
};

export const buttonStyle =
'flex h-48px w-48px items-center justify-center rounded border border-transparent bg-purpleLinear p-3 transition-all duration-300 ease-in-out hover:border-hoverWhite hover:cursor-pointer disabled:opacity-50 disabled:cursor-default disabled:border-transparent';

export const MAX_64_BIT_INTEGER_PARAMETER = '9223372036854775807';
export const MIN_64_BIT_INTEGER_PARAMETER = '-9223372036854775808';

Expand Down
Loading