Skip to content

Commit

Permalink
Adds Tailwind CSS, Mock Transaction Data, Search Function and Transac…
Browse files Browse the repository at this point in the history
…tion Results Page (MystenLabs#471)

* Implements a Tailwind CSS approach that compartmentalizes styling
* Adds a mock transaction JSON dataset for testing and to facilitate work on the UI while API is in development (see `./explorer/client/src/utils/transaction_mock.json`)
* Adds the Search Function
* Adds the Transaction Results page
* Implements 'Japanese Streetwear' look with Yoshimichi Ohira fonts from Google Fonts
* Updates the tests to reflect the new functionality
* Implements a logical structure to the `src` code with `pages` for complete pages and  `components` for things that are part of a page
  • Loading branch information
apburnie authored Feb 28, 2022
1 parent 0a96381 commit 527402a
Show file tree
Hide file tree
Showing 28 changed files with 559 additions and 122 deletions.
6 changes: 6 additions & 0 deletions explorer/client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,9 @@ Run linting check but also try to fix any issues.

Run prettier in watch mode and format any file that changes. (Also runs prettier once in the beginning for all the files)\
It can be useful during development to format automatically all the files that change.

## Deployment

For guidance on deployment, plese see here: https://create-react-app.dev/docs/deployment/.

Because of the addition of `react-router` further changes will be needed that depend on the exact infrastructure used. Please consult section **Serving Apps with Client-Side Routing**.
30 changes: 21 additions & 9 deletions explorer/client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion explorer/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,18 @@
"@types/node": "^16.11.24",
"@types/react": "^17.0.39",
"@types/react-dom": "^17.0.11",
"autoprefixer": "^10.4.2",
"concurrently": "^7.0.0",
"eslint-config-prettier": "^8.3.0",
"onchange": "^7.1.0",
"postcss": "^8.4.6",
"prettier": "2.5.1",
"react-scripts": "5.0.0",
"sass": "^1.49.7",
"stylelint": "^14.5.0",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-standard": "^25.0.0",
"stylelint-config-standard-scss": "^3.0.0",
"tailwindcss": "^3.0.23",
"typescript": "^4.5.5"
},
"dependencies": {
Expand Down
93 changes: 93 additions & 0 deletions explorer/client/src/__tests__/App.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { render, screen, fireEvent } from '@testing-library/react';
import { createMemoryHistory } from 'history';
import {
MemoryRouter,
unstable_HistoryRouter as HistoryRouter,
} from 'react-router-dom';

import App from '../app/App';

function expectHome() {
expect(screen.getByText(/Latest Transactions/i)).toBeInTheDocument();
}

function searchText(text: string) {
fireEvent.change(
screen.getByPlaceholderText(/Search transactions by ID/i),
{ target: { value: text } }
);
fireEvent.submit(screen.getByRole('form', { name: /search form/i }));
}

function expectTransactionStatus(result: 'fail' | 'success') {
expect(screen.getByTestId('transaction-status')).toHaveTextContent(result);
}

describe('App component', () => {
it('renders the home page', () => {
render(<App />, { wrapper: MemoryRouter });
expectHome();
});
it('redirects to home for every unknown path', () => {
render(
<MemoryRouter initialEntries={['/anything']}>
<App />
</MemoryRouter>
);
expectHome();
});
it('redirects to home for unknown path by replacing the history', () => {
const history = createMemoryHistory({ initialEntries: ['/anything'] });
render(
<HistoryRouter history={history}>
<App />
</HistoryRouter>
);
expectHome();
expect(history.index).toBe(0);
});
it('redirects to transaction details', () => {
render(<App />, { wrapper: MemoryRouter });
searchText(
'A1dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'
);
expect(screen.getByText('Transaction ID')).toBeInTheDocument();
expectTransactionStatus('success');
});
it('complains when transaction cannot be found', () => {
render(<App />, { wrapper: MemoryRouter });
searchText(
'A1ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddde'
);
expect(
screen.getByText('This transaction could not be found:')
).toBeInTheDocument();
});
it('details a transaction failure', () => {
render(<App />, { wrapper: MemoryRouter });
searchText(
'A2dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'
);
expectTransactionStatus('fail');
});

it('redirects to search result', () => {
render(<App />, { wrapper: MemoryRouter });
searchText('Mysten Labs');
expect(
screen.getByText('Search results for "Mysten Labs"')
).toBeInTheDocument();
});
it('returns home when Home is clicked', () => {
render(<App />, { wrapper: MemoryRouter });
searchText('Mysten Labs');
fireEvent.click(screen.getByRole('link', { name: /home button/i }));
expectHome();
});
it('returns home when Title Logo is clicked', () => {
render(<App />, { wrapper: MemoryRouter });
searchText('Mysten Labs');
fireEvent.click(screen.getByRole('link', { name: /logo/i }));
expectHome();
});
});
11 changes: 11 additions & 0 deletions explorer/client/src/app/App.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.app {
@apply font-sans w-screen;
}

.search > h2 {
@apply ml-[5vw] mb-[1vh];
}

.search {
@apply bg-black text-white pb-4 w-[100vw];
}
49 changes: 0 additions & 49 deletions explorer/client/src/app/App.test.tsx

This file was deleted.

16 changes: 12 additions & 4 deletions explorer/client/src/app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import NavigationHeader from '../nav-header/NavigationHeader';
import Footer from '../components/footer/Footer';
import Header from '../components/header/Header';
import Search from '../components/search/Search';
import AppRoutes from '../pages/config/AppRoutes';
import styles from './App.module.css';

function App() {
return (
<>
<NavigationHeader />
<div className={styles.app}>
<Header />
<div className={styles.search}>
<h2>The Sui Explorer</h2>
<Search />
</div>
<main>
<AppRoutes />
</main>
</>
<Footer />
</div>
);
}

Expand Down
9 changes: 9 additions & 0 deletions explorer/client/src/components/external-link/ExternalLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function ExternalLink({ href, label }: { href: string; label: string }) {
return (
<a href={href} target="_blank" rel="noreferrer noopener">
{label}
</a>
);
}

export default ExternalLink;
7 changes: 7 additions & 0 deletions explorer/client/src/components/footer/Footer.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.footer {
@apply fixed bottom-0 bg-black w-full px-[5vw];
}

.links > a {
@apply text-white no-underline hover:underline leading-[5vh] mr-[5vw];
}
26 changes: 26 additions & 0 deletions explorer/client/src/components/footer/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Link } from 'react-router-dom';

import ExternalLink from '../external-link/ExternalLink';
import styles from './Footer.module.css';

function Footer() {
return (
<footer className={styles.footer}>
<nav className={styles.links}>
<Link to="/" aria-label="home button">
Home
</Link>
<ExternalLink
href="https://mystenlabs.com/"
label="Mysten Labs"
/>
<ExternalLink
href="https://devportal-30dd0.web.app/"
label="Developer Hub"
/>
</nav>
</footer>
);
}

export default Footer;
12 changes: 12 additions & 0 deletions explorer/client/src/components/header/Header.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.logo {
@apply font-advanced text-2xl lg:text-4xl text-black
no-underline;
}

.nav {
@apply mt-[1vh] ml-[5vw];
}

header {
@apply h-[2rem];
}
17 changes: 17 additions & 0 deletions explorer/client/src/components/header/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Link } from 'react-router-dom';

import styles from './Header.module.css';

const Header = () => {
return (
<header>
<nav className={styles.nav}>
<Link to="/" aria-label="logo" className={styles.logo}>
Mysten Labs
</Link>
</nav>
</header>
);
};

export default Header;
Loading

0 comments on commit 527402a

Please sign in to comment.