Skip to content

Commit

Permalink
[ENH] Implemented app skeleton (#36)
Browse files Browse the repository at this point in the history
* Implemented `Landing` component

* Implemented `Upload` component

* Implemented `ColumnAnnotation` component

* Implemented `ValueAnnotation` component

* Implemented `Download` component

* Implemented `NavigationButton` component

* Implemented component test for `NavigationButton`

* Implemented component test for `Landing`

* Implemented component test for `ColumnAnnotation`

* Implemented component test for `Upload`

* Implemented test for `ValueAnnotation` component

* Implemented component test for `Download`

* Removed `Dummy` tests

* Implemented store

* Added a unit test for `setCurrentView` action

* Updated `App` component to render the appropriate view

* Implemented `Simple` e2e test

* Added `themes` module and implemented `NBTheme`

* Set up `ThemeProvider`

* Fixed typo

* Fixed `Download` component test

Careful when copy pasting

* Small refactor
  • Loading branch information
rmanaem authored Feb 13, 2025
1 parent 7902050 commit dacd788
Show file tree
Hide file tree
Showing 20 changed files with 263 additions and 15 deletions.
8 changes: 8 additions & 0 deletions cypress/component/ColumAnnotation.cy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import ColumnAnnotation from '../../src/components/ColumnAnnotation';

describe('ColumnAnnotation', () => {
it('should render correctly', () => {
cy.mount(<ColumnAnnotation />);
cy.contains('Column Annotation');
});
});
8 changes: 8 additions & 0 deletions cypress/component/Download.cy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Download from '../../src/components/Download';

describe('Download', () => {
it('should render correctly', () => {
cy.mount(<Download />);
cy.contains('Download');
});
});
8 changes: 8 additions & 0 deletions cypress/component/Landing.cy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Landing from '../../src/components/Landing';

describe('Landing', () => {
it('should render correctly', () => {
cy.mount(<Landing />);
cy.contains('Welcome');
});
});
24 changes: 24 additions & 0 deletions cypress/component/NavigationButton.cy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import NavigationButton from '../../src/components/NavigationButton';
import useStore from '../../src/stores/store';

const props = {
label: 'Next',
viewToNavigateTo: 'some view',
};

describe('NavigationButton', () => {
it('should render correctly', () => {
cy.mount(<NavigationButton label={props.label} viewToNavigateTo={props.viewToNavigateTo} />);
cy.contains(props.label);
});

it('should call setCurrentView with the correct view when clicked', () => {
cy.spy(useStore.getState(), 'setCurrentView').as('setCurrentViewSpy');

cy.mount(<NavigationButton label={props.label} viewToNavigateTo={props.viewToNavigateTo} />);

cy.contains(props.label).click();

cy.get('@setCurrentViewSpy').should('have.been.calledWith', props.viewToNavigateTo);
});
});
8 changes: 8 additions & 0 deletions cypress/component/Upload.cy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Upload from '../../src/components/Upload';

describe('Upload', () => {
it('should render correctly', () => {
cy.mount(<Upload />);
cy.contains('Upload');
});
});
8 changes: 8 additions & 0 deletions cypress/component/ValueAnnotation.cy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import ValueAnnotation from '../../src/components/ValueAnnotation';

describe('ValueAnnotation', () => {
it('should render correctly', () => {
cy.mount(<ValueAnnotation />);
cy.contains('Value Annotation');
});
});
6 changes: 0 additions & 6 deletions cypress/e2e/Dummy.cy.ts

This file was deleted.

17 changes: 17 additions & 0 deletions cypress/e2e/Simple.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
describe('Simlpe e2e test', () => {
it('Steps through different app views', () => {
cy.visit('http://localhost:5173');
cy.contains('Welcome');
cy.contains('Start - Upload').click();
cy.contains('Upload');
cy.contains('Next - Column Annotation').click();
cy.contains('Column Annotation');
cy.contains('Next - Value Annotation').click();
cy.contains('Value Annotation');
// reload to make sure the currentView persists
cy.reload();
cy.contains('Value Annotation');
cy.contains('Next - Download').click();
cy.contains('Download');
});
});
28 changes: 27 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
import useStore from './stores/store';
import Landing from './components/Landing';
import Upload from './components/Upload';
import ColumnAnnotation from './components/ColumnAnnotation';
import ValueAnnotation from './components/ValueAnnotation';
import Download from './components/Download';

function App() {
return <p>Hello World</p>;
const currentView = useStore((state) => state.currentView);

const renderView = () => {
switch (currentView) {
case 'ladning':
return <Landing />;
case 'upload':
return <Upload />;
case 'columnAnnotation':
return <ColumnAnnotation />;
case 'valueAnnotation':
return <ValueAnnotation />;
case 'download':
return <Download />;
default:
return <Landing />;
}
};

return <div>{renderView()}</div>;
}

export default App;
15 changes: 15 additions & 0 deletions src/components/ColumnAnnotation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import NavigationButton from './NavigationButton';

function ColumnAnnotation() {
return (
<div className="flex flex-col items-center">
<h1>Column Annotation</h1>
<div className="flex space-x-4">
<NavigationButton label="Back - Upload" viewToNavigateTo="upload" />
<NavigationButton label="Next - Value Annotation" viewToNavigateTo="valueAnnotation" />
</div>
</div>
);
}

export default ColumnAnnotation;
12 changes: 12 additions & 0 deletions src/components/Download.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import NavigationButton from './NavigationButton';

function Download() {
return (
<div className="flex flex-col items-center">
<h1>Download</h1>
<NavigationButton label="Back - Value Annotation" viewToNavigateTo="valueAnnotation" />
</div>
);
}

export default Download;
12 changes: 12 additions & 0 deletions src/components/Landing.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import NavigationButton from './NavigationButton';

function Landing() {
return (
<div className="flex flex-col items-center">
<h1>Welcome</h1>
<NavigationButton label="Start - Upload" viewToNavigateTo="upload" />
</div>
);
}

export default Landing;
24 changes: 24 additions & 0 deletions src/components/NavigationButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Button } from '@mui/material';
import useStore from '../stores/store';

function NavigationButton({
label,
viewToNavigateTo,
}: {
label: string;
viewToNavigateTo: string;
}) {
const setCurrentView = useStore((state) => state.setCurrentView);

const handleClick = () => {
setCurrentView(viewToNavigateTo);
};

return (
<Button variant="contained" onClick={handleClick}>
{label}
</Button>
);
}

export default NavigationButton;
15 changes: 15 additions & 0 deletions src/components/Upload.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import NavigationButton from './NavigationButton';

function Upload() {
return (
<div className="flex flex-col items-center">
<h1>Upload</h1>
<div className="flex space-x-4">
<NavigationButton label="Back - Welcome" viewToNavigateTo="landing" />
<NavigationButton label="Next - Column Annotation" viewToNavigateTo="columnAnnotation" />
</div>
</div>
);
}

export default Upload;
15 changes: 15 additions & 0 deletions src/components/ValueAnnotation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import NavigationButton from './NavigationButton';

function ValueAnnotation() {
return (
<div className="flex flex-col items-center">
<h1>Value Annotation</h1>
<div className="flex space-x-4">
<NavigationButton label="Back - Column Annotation" viewToNavigateTo="columnAnnotation" />
<NavigationButton label="Next - Download" viewToNavigateTo="download" />
</div>
</div>
);
}

export default ValueAnnotation;
6 changes: 0 additions & 6 deletions src/dummy.test.ts

This file was deleted.

7 changes: 5 additions & 2 deletions src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import { StyledEngineProvider } from '@mui/material/styles';
import { StyledEngineProvider, ThemeProvider } from '@mui/material/styles';
import App from './App';
import NBTheme from './theme';
import './index.css';

ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
{/* CSS injection order for MUI and tailwind: https://mui.com/material-ui/guides/interoperability/#tailwind-css */}
<StyledEngineProvider injectFirst>
<App />
<ThemeProvider theme={NBTheme}>
<App />
</ThemeProvider>
</StyledEngineProvider>
</React.StrictMode>
);
13 changes: 13 additions & 0 deletions src/stores/store.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { act, renderHook } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import useStore from './store';

describe('store actions', () => {
it('should set currentView', () => {
const { result } = renderHook(() => useStore());
act(() => {
result.current.setCurrentView('upload');
});
expect(result.current.currentView).toBe('upload');
});
});
23 changes: 23 additions & 0 deletions src/stores/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';

type Store = {
currentView: string;
setCurrentView: (view: string) => void;
};

const useStore = create<Store>()(
persist(
(set) => ({
currentView: 'landing',
setCurrentView: (view: string) => set({ currentView: view }),
}),
{
name: 'store',
partialize: (state) => ({ currentView: state.currentView }),
storage: createJSONStorage(() => sessionStorage),
}
)
);

export default useStore;
21 changes: 21 additions & 0 deletions src/theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { createTheme } from '@mui/material';

const NBTheme = createTheme({
palette: {
primary: {
light: '#F5A89B',
main: '#D9748D',
dark: '#A8556F',
contrastText: '#FFFFFF',
},
},
components: {
MuiButton: {
defaultProps: {
sx: { textTransform: 'none' },
},
},
},
});

export default NBTheme;

0 comments on commit dacd788

Please sign in to comment.