Skip to content

Commit

Permalink
chore(content-explorer): Migrate Content
Browse files Browse the repository at this point in the history
  • Loading branch information
greg-in-a-box committed Jan 10, 2025
1 parent 200420d commit ba0db50
Show file tree
Hide file tree
Showing 20 changed files with 552 additions and 87 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
/**
* @flow
* @file Empty state component
* @author Box
*/

import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import ErrorEmptyState from '../../../icons/states/ErrorEmptyState';
Expand All @@ -18,10 +12,13 @@ import './EmptyState.scss';

type Props = {
isLoading: boolean,
view: View,
view: View
};

const EmptyState = ({ view, isLoading }: Props) => {
const EmptyState = ({
view,
isLoading,
}: Props) => {
let type;
const message =
isLoading && (view === VIEW_FOLDER || view === VIEW_METADATA) ? (
Expand Down
6 changes: 6 additions & 0 deletions src/elements/common/empty-state/EmptyState.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,10 @@
align-items: center;
justify-content: center;
text-align: center;

svg {
width: 130px;
height: 130px;
margin-bottom: 10px;
}
}
48 changes: 48 additions & 0 deletions src/elements/common/empty-state/EmptyState.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { Files, FolderFloat, HatWand, OpenBook } from '@box/blueprint-web-assets/illustrations/Medium';

import messages from '../messages';
import { VIEW_ERROR, VIEW_FOLDER, VIEW_METADATA, VIEW_SEARCH, VIEW_SELECTED } from '../../../constants';
import type { View } from '../../../common/types/core';

import './EmptyState.scss';

export interface EmptyStateProps {
isLoading: boolean;
view: View;
}

const EmptyState = ({ view, isLoading }: EmptyStateProps) => {
let type;
const message =
isLoading && (view === VIEW_FOLDER || view === VIEW_METADATA) ? (
<FormattedMessage {...messages.loadingState} />
) : (
<FormattedMessage {...messages[`${view}State`]} />
);

switch (view) {
case VIEW_ERROR:
type = <HatWand />;
break;
case VIEW_SELECTED:
type = <Files />;
break;
case VIEW_SEARCH:
type = <OpenBook />;
break;
default:
type = <FolderFloat />;
break;
}

return (
<div className="be-empty">
{type}
<div>{message}</div>
</div>
);
};

export default EmptyState;
1 change: 1 addition & 0 deletions src/elements/common/empty-state/index.js.flow
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {default} from './EmptyState';
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
// @flow
export { default } from './EmptyState';
Original file line number Diff line number Diff line change
@@ -1,28 +1,22 @@
/**
* @flow
* @file Progress Bar component
* @author Box
*/

import React, { PureComponent } from 'react';
import React, {PureComponent} from 'react';
import './ProgressBar.scss';

type Props = {
percent: number,
percent: number
};

type State = {
percent: number,
percent: number
};

class ProgressBar extends PureComponent<Props, State> {
props: Props;

state: State;

timeout: TimeoutID;
timeout: number;

interval: IntervalID;
interval: number;

static defaultProps = { percent: 0 };

Expand All @@ -33,7 +27,9 @@ class ProgressBar extends PureComponent<Props, State> {
*/
constructor(props: Props) {
super(props);
const { percent }: State = props;
const {
percent,
}: State = props;
this.state = { percent };
}

Expand Down Expand Up @@ -61,7 +57,9 @@ class ProgressBar extends PureComponent<Props, State> {
* @return {void}
*/
componentDidUpdate(prevProps: Props): void {
const { percent }: Props = this.props;
const {
percent,
}: Props = this.props;

if (prevProps.percent !== percent) {
this.clearTimeoutAndInterval();
Expand All @@ -85,7 +83,9 @@ class ProgressBar extends PureComponent<Props, State> {
* @return {void}
*/
startProgress = () => {
const { percent }: State = this.state;
const {
percent,
}: State = this.state;
if (percent === 0) {
this.interval = setInterval(this.incrementProgress, 100);
} else if (percent === 100) {
Expand Down Expand Up @@ -121,7 +121,9 @@ class ProgressBar extends PureComponent<Props, State> {
* @return {void}
*/
render() {
const { percent }: State = this.state;
const {
percent,
}: State = this.state;
const containerStyle = {
opacity: percent > 0 && percent < 100 ? 1 : 0,
transitionDelay: percent > 0 && percent < 100 ? '0' : '0.4s',
Expand Down
67 changes: 67 additions & 0 deletions src/elements/common/progress-bar/ProgressBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React, { useCallback, useEffect, useState, useRef } from 'react';
import './ProgressBar.scss';

export interface ProgressBarProps {
percent: number;
}

const ProgressBar = ({ percent: initialPercent = 0 }: ProgressBarProps) => {
const [percent, setPercent] = useState(initialPercent);
const intervalRef = useRef<number | null>(null);
const timeoutRef = useRef<number | null>(null);

const clearTimeoutAndInterval = () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
};

const incrementProgress = () => {
setPercent(prevPercent => {
const newPercent = Math.min(prevPercent + 2 / (prevPercent || 1), 100);
if (newPercent === 100) {
clearTimeoutAndInterval();
}
0;
return newPercent;
});
};

const resetProgress = () => {
setPercent(0);
};

const startProgress = useCallback(() => {
if (percent === 0) {
intervalRef.current = window.setInterval(incrementProgress, 100);
} else if (percent === 100) {
timeoutRef.current = window.setTimeout(resetProgress, 600);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
startProgress();
return () => clearTimeoutAndInterval();
}, [percent, startProgress]);

useEffect(() => {
setPercent(initialPercent);
}, [initialPercent]);

const containerStyle = {
opacity: percent > 0 && percent < 100 ? 1 : 0,
transitionDelay: percent > 0 && percent < 100 ? '0' : '0.4s',
} as const;

return (
<div className="be-progress-container" style={containerStyle}>
<div className="be-progress" role="progressbar" style={{ width: `${percent}%` }} />
</div>
);
};

export default ProgressBar;
12 changes: 0 additions & 12 deletions src/elements/common/progress-bar/__tests__/ProgressBar.test.js

This file was deleted.

32 changes: 32 additions & 0 deletions src/elements/common/progress-bar/__tests__/ProgressBar.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as React from 'react';
import { act, render, screen } from '../../../../test-utils/testing-library';
import ProgressBar from '../ProgressBar';

describe('ProgressBar', () => {
test('renders with initial percent', () => {
render(<ProgressBar percent={20} />);
const progressBar = screen.getByRole('progressbar');
expect(progressBar).toHaveStyle({ width: '20%' });
});

test('updates percent when props change', () => {
const { rerender } = render(<ProgressBar percent={20} />);
rerender(<ProgressBar percent={30} />);
const progressBar = screen.getByRole('progressbar');
expect(progressBar).toHaveStyle({ width: '30%' });
});

test('resets percent to 0 after reaching 100%', async () => {
jest.useFakeTimers();
render(<ProgressBar percent={0} />);

act(() => {
jest.advanceTimersByTime(250000); // yes it has to be at least 250000ms, any less it will not hit 100%
});

const progressBar = await screen.getByRole('progressbar');
expect(progressBar).toHaveStyle({ width: '100%' });

jest.useRealTimers();
});
});
1 change: 1 addition & 0 deletions src/elements/common/progress-bar/index.js.flow
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {default} from './ProgressBar';
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
// @flow
export { default } from './ProgressBar';
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
/**
* @flow
* @file File picker header and list component
* @author Box
*/

import * as React from 'react';
import EmptyState from '../common/empty-state';
import ProgressBar from '../common/progress-bar';
Expand All @@ -25,7 +19,9 @@ import './Content.scss';
* @return {boolean} empty or not
*/
function isEmpty(view: View, currentCollection: Collection, fieldsToShow: FieldsToShow): boolean {
const { items = [] }: Collection = currentCollection;
const {
items = [],
}: Collection = currentCollection;
return view === VIEW_ERROR || !items.length || (view === VIEW_METADATA && !fieldsToShow.length);
}

Expand All @@ -42,21 +38,21 @@ type Props = {
isMedium: boolean,
isSmall: boolean,
isTouch: boolean,
onItemClick: Function,
onItemDelete: Function,
onItemDownload: Function,
onItemPreview: Function,
onItemRename: Function,
onItemSelect: Function,
onItemShare: Function,
onMetadataUpdate: Function,
onSortChange: Function,
onItemClick: any,
onItemDelete: any,
onItemDownload: any,
onItemPreview: any,
onItemRename: any,
onItemSelect: any,
onItemShare: any,
onMetadataUpdate: any,
onSortChange: any,
rootElement?: HTMLElement,
rootId: string,
selected?: BoxItem,
tableRef: Function,
tableRef: any,
view: View,
viewMode?: ViewMode,
viewMode?: ViewMode
};

const Content = ({
Expand Down
Loading

0 comments on commit ba0db50

Please sign in to comment.