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

feat: interface-select-content UI & landing UI changes added #10

Merged
merged 2 commits into from
Sep 12, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
47 changes: 31 additions & 16 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,63 @@ import { useDisclosure } from '@nextui-org/react';
import CodeEditor from '@/components/code-editor';
import Header from '@/components/header';
import Result from '@/components/result';
import { extractInterfaceNames } from '@/utils';
import { extractInterfaceNames, generateMocks } from '@/utils';
import { Initials } from '@/config/constants';
import InterfaceSelectModal from '@/components/interface-select-modal';
import { RowNumber } from '@/types';

const Home: FC = () => {
const { isOpen, onOpen, onOpenChange } = useDisclosure();
const detectedInterfaces = useRef<string[] | null>(null);
const mockResult = useRef<string | null>(JSON.stringify(Initials.DefaultMockResult));
const [code, setCode] = useState<string>(Initials.DefaultInterface);
const [numberOfRows, setNumberOfRows] = useState(new Set(['1']));
const [numberOfRows, setNumberOfRows] = useState<RowNumber>('1');
const [interfaces, setInterfaces] = useState<Set<string> | any>(
new Set(detectedInterfaces?.current),
);

const selectedInterfaces = useRef<string[] | null>(null);
const handleChipClose = (closedInterface: string): void => {
if (interfaces.size === 1) return;
const newSelectedKeys = new Set(Array.from(interfaces)?.filter(key => key !== closedInterface));
setInterfaces(newSelectedKeys);
};

const handleOnGenerate = (): void => {
const interfaceNamesToMock = extractInterfaceNames(code);
selectedInterfaces.current = interfaceNamesToMock;
detectedInterfaces.current = interfaceNamesToMock;
setInterfaces(new Set(interfaceNamesToMock));
onOpen();
};

// TODO: fix any type here
const handleOnRowCountChange = (newRowCount: any): void => {
setNumberOfRows(newRowCount);
};

const handleOnCodeChange = (newCode: string): void => {
setCode(newCode);
};

const handleOnMockGenerate = (): void => {
const generatedMocks = generateMocks(code, Array.from(interfaces));
mockResult.current = JSON.stringify(generatedMocks, null, 2);

onOpenChange();
};

return (
<section className='h-full'>
<Header
onGenerate={handleOnGenerate}
numberOfRows={numberOfRows}
onRowCountChange={handleOnRowCountChange}
/>
<Header onGenerate={handleOnGenerate} />
<div className='flex justify-center gap-6 h-[calc(100vh-12rem)]'>
<CodeEditor onCodeChange={handleOnCodeChange} initialCode={code} />
<Result />
<Result mockResult={mockResult?.current ?? ''} />
</div>

<InterfaceSelectModal
isOpen={isOpen}
detectedInterfaces={detectedInterfaces.current}
numberOfRows={numberOfRows}
onOpenChange={onOpenChange}
selectedInterfaces={selectedInterfaces.current}
onMockGenerate={handleOnMockGenerate}
setNumberOfRows={setNumberOfRows}
interfaces={interfaces}
setInterfaces={setInterfaces}
handleChipClose={handleChipClose}
/>
</section>
);
Expand Down
38 changes: 2 additions & 36 deletions components/header/index.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,17 @@
import React, { FC } from 'react';
import {
Dropdown,
DropdownTrigger,
DropdownMenu,
DropdownItem,
Button,
Selection,
} from '@nextui-org/react';
import { Button } from '@nextui-org/react';

type Props = {
onGenerate: () => void;
onRowCountChange: (rowCount: Selection) => void;
numberOfRows: any;
};

const Header: FC<Props> = ({ onGenerate, onRowCountChange, numberOfRows }) => {
const selectedValue = React.useMemo(
() => Array.from(numberOfRows).join(', ').replaceAll('_', ' '),
[numberOfRows],
);

const Header: FC<Props> = ({ onGenerate }) => {
return (
<div className='pb-6 text-center flex items-center justify-between'>
<h1 className='tracking-tight inline font-semibold text-[2.3rem] lg:text-3xl'>
Generate 𝔽𝕒𝕜𝕖 Data
</h1>
<div className='flex items-center gap-4'>
<Dropdown>
<DropdownTrigger>
<Button variant='bordered' className='capitalize'>
{`#️⃣ Scale [${selectedValue} of row${Number(selectedValue) > 1 ? 's' : ''}]`}
</Button>
</DropdownTrigger>
<DropdownMenu
aria-label='row-count-select'
variant='flat'
disallowEmptySelection
selectionMode='single'
selectedKeys={numberOfRows}
onSelectionChange={onRowCountChange}
>
<DropdownItem key='1'>1</DropdownItem>
<DropdownItem key='10'>10</DropdownItem>
<DropdownItem key='50'>50</DropdownItem>
</DropdownMenu>
</Dropdown>

<Button color='primary' variant='shadow' onClick={onGenerate}>
🪄 Generate
</Button>
Expand Down
105 changes: 64 additions & 41 deletions components/interface-select-content/index.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
import React, { FC, useState } from 'react';
import { Listbox, ListboxItem } from '@nextui-org/react';
import React, { FC, Key } from 'react';
import { Chip } from '@nextui-org/react';
import { Colors } from '@/config/constants';
import { Listbox, ListboxItem, Radio, RadioGroup } from '@nextui-org/react';
import { RowNumber } from '@/types';

const InterfaceSelectContent: FC = () => {
const [selectedKeys, setSelectedKeys] = useState<Set<string> | any>(new Set(['text']));
interface Props {
detectedInterfaces: string[];
interfaces: Set<string>;
numberOfRows: RowNumber;
setInterfaces: (keys: Set<Key>) => void;
handleChipClose: (closedInterface: string) => void;
setNumberOfRows: (numberOfRows: RowNumber) => void;
}

const backgroundColors: string[] = [
'bg-primary',
'bg-secondary',
'bg-warning',
'bg-danger',
'bg-default',
];
const handleChipClose = (closedInterface: string): void => {
if (selectedKeys.size === 1) return;
const newSelectedKeys = new Set(
Array.from(selectedKeys).filter(key => key !== closedInterface),
);
setSelectedKeys(newSelectedKeys);
const InterfaceSelectContent: FC<Props> = ({
detectedInterfaces,
numberOfRows,
setNumberOfRows,
interfaces,
setInterfaces,
handleChipClose,
}) => {
const handleNumberOfRowsChange = (value: string): void => {
setNumberOfRows(value as RowNumber);
};

const handleInterfaceChange = (selectedInterfaces: Set<Key>): void => {
if (selectedInterfaces?.size > 1) setNumberOfRows('1');
setInterfaces(selectedInterfaces);
};

return (
Expand All @@ -27,33 +37,46 @@ const InterfaceSelectContent: FC = () => {
variant='flat'
disallowEmptySelection
selectionMode='multiple'
selectedKeys={selectedKeys}
onSelectionChange={setSelectedKeys}
selectedKeys={interfaces}
onSelectionChange={(keys): void => handleInterfaceChange(new Set(keys))}
>
<ListboxItem key='text'>⚡ Text</ListboxItem>
<ListboxItem key='number'>⚡ Number</ListboxItem>
<ListboxItem key='date'>⚡ Date</ListboxItem>
<ListboxItem key='single_date'>⚡ Single Date</ListboxItem>
<ListboxItem key='iteration'>⚡ Iteration</ListboxItem>
{detectedInterfaces?.map((interfaceName: any) => (
<ListboxItem key={interfaceName}>{`⚡ ${interfaceName}`}</ListboxItem>
)) || null}
</Listbox>
<div className='flex flex-wrap gap-2 items-center'>
<p className='text-small text-default-500'>Selected interfaces: </p>
{Array.from(selectedKeys).map((selectedInterface: any, index: number) => (
<Chip
size='sm'
radius='full'
variant='flat'
key={selectedInterface}
onClose={(): void => handleChipClose(selectedInterface)}
classNames={{
base: backgroundColors[index % backgroundColors.length],
content: 'text-white',
}}
>
{selectedInterface}
</Chip>
))}

<div className='mb-4'>
<p className='mb-3'>Selected interfaces </p>
<div className='flex flex-wrap gap-2 items-center'>
{Array.from(interfaces).map((interfaceName: any, index: number) => (
<Chip
size='sm'
radius='full'
variant='flat'
key={interfaceName}
onClose={(): void => handleChipClose(interfaceName)}
classNames={{
base: Colors.ChipClors[index % Colors.ChipClors.length],
content: 'text-white',
}}
>
{interfaceName}
</Chip>
))}
</div>
</div>
{interfaces.size === 1 ? (
<RadioGroup
label={<p className='text-white'>Scale number of rows</p>}
orientation='horizontal'
value={numberOfRows}
onValueChange={handleNumberOfRowsChange}
>
<Radio value='1'>1 Row</Radio>
<Radio value='10'>10 Rows</Radio>
<Radio value='50'>50 Rows</Radio>
</RadioGroup>
) : null}
</div>
);
};
Expand Down
36 changes: 29 additions & 7 deletions components/interface-select-modal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FC } from 'react';
import React, { FC, Key } from 'react';
import {
Modal,
ModalContent,
Expand All @@ -8,16 +8,31 @@ import {
Button,
} from '@nextui-org/react';
import InterfaceSelectContent from '@/components/interface-select-content';
import { RowNumber } from '@/types';

interface Props {
isOpen: boolean;
selectedInterfaces: string[] | null;
detectedInterfaces: string[] | null;
numberOfRows: RowNumber;
interfaces: Set<string>;
onOpenChange: () => void;
setNumberOfRows: (numberOfRows: RowNumber) => void;
setInterfaces: (keys: Set<Key>) => void;
handleChipClose: (closedInterface: string) => void;
onMockGenerate: () => void;
}

const InterfaceSelectModal: FC<Props> = ({ isOpen, onOpenChange, selectedInterfaces }) => {
console.log('🚀 ~ file: index.tsx:18 ~ selectedInterfaces:', selectedInterfaces);

const InterfaceSelectModal: FC<Props> = ({
isOpen,
detectedInterfaces,
numberOfRows,
interfaces,
setNumberOfRows,
onOpenChange,
setInterfaces,
handleChipClose,
onMockGenerate,
}) => {
return (
<>
<Modal isOpen={isOpen} onOpenChange={onOpenChange}>
Expand All @@ -29,13 +44,20 @@ const InterfaceSelectModal: FC<Props> = ({ isOpen, onOpenChange, selectedInterfa
</ModalHeader>
<ModalBody>
<p>Please select the interfaces you want to generate mock data for.</p>
<InterfaceSelectContent />
<InterfaceSelectContent
detectedInterfaces={detectedInterfaces ?? []}
numberOfRows={numberOfRows}
setNumberOfRows={setNumberOfRows}
interfaces={interfaces}
setInterfaces={setInterfaces}
handleChipClose={handleChipClose}
/>
</ModalBody>
<ModalFooter>
<Button color='danger' variant='bordered' onPress={onClose}>
Close
</Button>
<Button color='primary' onPress={onClose}>
<Button color='primary' onPress={onMockGenerate}>
🪄 Generate
</Button>
</ModalFooter>
Expand Down
Loading