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: extract & clean interfaces #9

Merged
merged 2 commits into from
Sep 10, 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
36 changes: 21 additions & 15 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
'use client';
import { FC, useState } from 'react';
import { FC, useRef, useState } from 'react';
import { useDisclosure } from '@nextui-org/react';
import CodeEditor from '@/components/code-editor';
import Header from '@/components/header';
import Result from '@/components/result';

const DEFAULT_INTERFACE = `// You can use typescript interfaces like following;

interface Person {
id: number;
firstName: string;
lastName: string;
age: number;
bio: string;
}
`;
import { extractInterfaceNames } from '@/utils';
import { Initials } from '@/config/constants';
import InterfaceSelectModal from '@/components/interface-select-modal';

const Home: FC = () => {
const [code, setCode] = useState<string>(DEFAULT_INTERFACE);
const [numberOfRows, setNumberOfRows] = useState(new Set(['10']));
const { isOpen, onOpen, onOpenChange } = useDisclosure();
const [code, setCode] = useState<string>(Initials.DefaultInterface);
const [numberOfRows, setNumberOfRows] = useState(new Set(['1']));

const selectedInterfaces = useRef<string[] | null>(null);

const handleOnGenerate = (): void => {
console.log('*********', code);
const interfaceNamesToMock = extractInterfaceNames(code);
selectedInterfaces.current = interfaceNamesToMock;
onOpen();
};

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

const handleOnCodeChange = (newCode: string): void => {
setCode(newCode);
};
Expand All @@ -41,6 +41,12 @@ const Home: FC = () => {
<CodeEditor onCodeChange={handleOnCodeChange} initialCode={code} />
<Result />
</div>

<InterfaceSelectModal
isOpen={isOpen}
onOpenChange={onOpenChange}
selectedInterfaces={selectedInterfaces.current}
/>
</section>
);
};
Expand Down
8 changes: 4 additions & 4 deletions components/header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,26 @@ const Header: FC<Props> = ({ onGenerate, onRowCountChange, numberOfRows }) => {
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 Fake Data
Generate 𝔽𝕒𝕜𝕖 Data
</h1>
<div className='flex items-center gap-4'>
<Dropdown>
<DropdownTrigger>
<Button variant='bordered' className='capitalize'>
{`#️⃣ Scale [${selectedValue} of rows]`}
{`#️⃣ Scale [${selectedValue} of row${Number(selectedValue) > 1 ? 's' : ''}]`}
</Button>
</DropdownTrigger>
<DropdownMenu
aria-label='Single selection example'
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>
<DropdownItem key='100'>100</DropdownItem>
</DropdownMenu>
</Dropdown>

Expand Down
61 changes: 61 additions & 0 deletions components/interface-select-content/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React, { FC, useState } from 'react';
import { Listbox, ListboxItem } from '@nextui-org/react';
import { Chip } from '@nextui-org/react';

const InterfaceSelectContent: FC = () => {
const [selectedKeys, setSelectedKeys] = useState<Set<string> | any>(new Set(['text']));

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);
};

return (
<div className='flex flex-col gap-2'>
<Listbox
aria-label='Multiple selection example'
variant='flat'
disallowEmptySelection
selectionMode='multiple'
selectedKeys={selectedKeys}
onSelectionChange={setSelectedKeys}
>
<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>
</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>
</div>
);
};

export default InterfaceSelectContent;
50 changes: 50 additions & 0 deletions components/interface-select-modal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React, { FC } from 'react';
import {
Modal,
ModalContent,
ModalHeader,
ModalBody,
ModalFooter,
Button,
} from '@nextui-org/react';
import InterfaceSelectContent from '@/components/interface-select-content';

interface Props {
isOpen: boolean;
selectedInterfaces: string[] | null;
onOpenChange: () => void;
}

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

return (
<>
<Modal isOpen={isOpen} onOpenChange={onOpenChange}>
<ModalContent>
{(onClose): any => (
<>
<ModalHeader className='flex flex-col gap-1'>
Following 𝕀𝕟𝕥𝕖𝕣𝕗𝕒𝕔𝕖𝕤 Detected
</ModalHeader>
<ModalBody>
<p>Please select the interfaces you want to generate mock data for.</p>
<InterfaceSelectContent />
</ModalBody>
<ModalFooter>
<Button color='danger' variant='bordered' onPress={onClose}>
Close
</Button>
<Button color='primary' onPress={onClose}>
🪄 Generate
</Button>
</ModalFooter>
</>
)}
</ModalContent>
</Modal>
</>
);
};

export default InterfaceSelectModal;
35 changes: 35 additions & 0 deletions config/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
export const Initials = {
DefaultInterface: `// You can use typescript interfaces like following;

interface Admin extends User {
adminRecord: AdminRecord;
}

interface Student extends User {
schoolRecord: SchoolRecord;
}

interface User {
firstName: string;
lastName: string;
username: string;
emailAddress: string;
}

interface AdminRecord {
studentsPassedEachYear: number[];
}

interface SchoolRecord {
startDate: string;
endDate: string;
isActive: boolean;
grades: number[];
}
`,
};

export const RegexExp = {
InterfaceName: /interface\s+(\w+)/g,
Interface: /interface\s+(\w+)\s*{[^}]*}/gs,
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"@nextui-org/kbd": "2.0.8",
"@nextui-org/link": "2.0.9",
"@nextui-org/navbar": "2.0.9",
"@nextui-org/react": "^2.0.24",
"@nextui-org/react": "^2.1.10",
"@nextui-org/snippet": "2.0.10",
"@nextui-org/switch": "2.0.9",
"@nextui-org/system": "2.0.5",
Expand All @@ -37,6 +37,7 @@
"eslint": "^8.47.0",
"eslint-config-next": "13.4.4",
"framer-motion": "^10.15.1",
"intermock": "^0.2.5",
"intl-messageformat": "^10.1.0",
"next": "13.4.13",
"next-themes": "^0.2.1",
Expand Down
7 changes: 7 additions & 0 deletions utils/extract-interface-names/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { RegexExp } from '@/config/constants';

export const extractInterfaceNames = (code: string): string[] => {
const matches = code.match(RegexExp.InterfaceName);

return matches ? matches.map(match => match.split(' ')[1]) : [];
};
15 changes: 15 additions & 0 deletions utils/generate-mocks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { mock } from 'intermock';

export const generateMocks = (
code: string,
selectedInterfaces: string[],
): string | Record<string | number, {}> => {
const mockedData = mock({
language: 'typescript',
files: [['docs', code]],
output: 'string',
interfaces: selectedInterfaces,
});

return mockedData;
};
2 changes: 2 additions & 0 deletions utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './extract-interface-names';
export * from './generate-mocks';
Loading