lbry-desktop/ui/component/common/tabs.jsx
mayeaux 8ff3b753ad
Move transactions from Settings to Wallet (#6871)
* remove unused conditional

get stuff ready for merge

bugfix and cleanup

requested changes

fixing flow errors

fix last flow error and touchups

fiat and lbc tabs coming along

support setting currency as the default tab via query param

add wallet fiat balance

fixing naming

add fiat transactions

using es6 to populate data

should be fine but keeps crashing

transaction listing working

add no transactions thing

about to add a third tab

add third tab

add card last 4 to transaction history

some renaming

show payments successfully

show filler for subscriptions

display if no transactions or subs

working but in the wrong component

approaching something thats working

showing total tipped amount

about to add last couple features

cleanup

More touchups

adding last features

calculate the total amount of unique creators tipped

couple touchups

remove transaction listings from settings

add view transactions buttons

small optimization

add subscriptions section

fix lot of linting errors and make command more userful

* some copy changes

* about to add last couple changes

* update still require verification

* fix button spacing

* hide subscriptions sections and fix links

* cleanups before merging

* more cleanup

* cleanup with last four fix

* changing tab functionality

* bugfix and fix presentation of cards

* fix transactions bug

* change order and remove logs

* remove unused code in account

* more linter fixes

* update account balance presentation

* fix flow errors
2021-08-13 13:59:43 -04:00

130 lines
3.6 KiB
JavaScript

// @flow
import React, { Fragment, useState, useRef, useContext, useLayoutEffect, createContext } from 'react';
import {
Tabs as ReachTabs,
Tab as ReachTab,
TabList as ReachTabList,
TabPanels as ReachTabPanels,
TabPanel as ReachTabPanel,
} from '@reach/tabs';
import classnames from 'classnames';
import { useRect } from '@reach/rect';
// Tabs are a compound component
// The components are used individually, but they will still interact and share state
// When using, at a minimum you must arrange the components in this pattern
// When the <Tab> at index 0 is active, the TabPanel at index 0 will be displayed
//
// <Tabs onChange={...} index={...}>
// <TabList>
// <Tab>Tab label 1</Tab>
// <Tab>Tab label 2</Tab>
// ...
// </TabList>
// <TabPanels>
// <TabPanel>Content for Tab 1</TabPanel>
// <TabPanel>Content for Tab 2</TabPanel>
// ...
// </TabPanels>
// </Tabs>
//
// the base @reach/tabs components handle all the focus/accessibility labels
// We're just adding some styling
type TabsProps = {
index?: number,
onChange?: number => void,
children: Array<React$Node>,
};
// Use context so child TabPanels can set the active tab, which is kept in Tabs' state
const AnimatedContext = createContext<any>();
function Tabs(props: TabsProps) {
// Store the position of the selected Tab so we can animate the "active" bar to its position
const [selectedRect, setSelectedRect] = useState(null);
// Create a ref of the parent element so we can measure the relative "left" for the bar for the child Tab's
const tabsRef = useRef();
const tabsRect = useRect(tabsRef);
const tabLabels = props.children[0];
const tabContent = props.children[1];
return (
<AnimatedContext.Provider value={setSelectedRect}>
<ReachTabs className="tabs" {...props} ref={tabsRef}>
{tabLabels}
<div
className="tab__divider"
style={{
left: selectedRect && tabsRect && selectedRect.left - tabsRect.left,
width: selectedRect && selectedRect.width,
}}
/>
{tabContent}
</ReachTabs>
</AnimatedContext.Provider>
);
}
//
// The wrapper for the list of tab labels that users can click
type TabListProps = {
className?: string,
};
function TabList(props: TabListProps) {
const { className, ...rest } = props;
return <ReachTabList className={classnames('tabs__list', className)} {...rest} />;
}
//
// The links that users click
// Accesses `setSelectedRect` from context to set itself as active if needed
// Flow doesn't understand we don't have to pass it in ourselves
type TabProps = {
isSelected?: Boolean,
};
function Tab(props: TabProps) {
// @reach/tabs provides an `isSelected` prop
// We could also useContext to read it manually
const { isSelected } = props;
// Each tab measures itself
const ref = useRef();
const rect = useRect(ref, isSelected);
// and calls up to the parent when it becomes selected
// we useLayoutEffect to avoid flicker
const setSelectedRect = useContext(AnimatedContext);
useLayoutEffect(() => {
if (isSelected) setSelectedRect(rect);
}, [isSelected, rect, setSelectedRect]);
return <ReachTab ref={ref} {...props} className="tab" />;
}
//
// The wrapper for TabPanel
type TabPanelsProps = {
header?: React$Node,
};
function TabPanels(props: TabPanelsProps) {
const { header, ...rest } = props;
return (
<Fragment>
{header}
<ReachTabPanels {...rest} />
</Fragment>
);
}
//
// The wrapper for content when it's associated Tab is selected
function TabPanel(props: any) {
return <ReachTabPanel className="tab__panel" {...props} />;
}
export { Tabs, TabList, Tab, TabPanels, TabPanel };