From e2d8932df49d264ac76aaa2236e1a0293729e6be Mon Sep 17 00:00:00 2001 From: Sidharth Sethi Date: Thu, 6 Oct 2022 23:32:50 +0530 Subject: [PATCH 1/4] Sorting Tool --- __TESTS__/sorting.spec.tsx | 99 +++++++++++++++ pages/sorting.tsx | 251 +++++++++++++++++++++++++++++++++++++ 2 files changed, 350 insertions(+) create mode 100644 __TESTS__/sorting.spec.tsx create mode 100644 pages/sorting.tsx diff --git a/__TESTS__/sorting.spec.tsx b/__TESTS__/sorting.spec.tsx new file mode 100644 index 0000000..c8d1b1c --- /dev/null +++ b/__TESTS__/sorting.spec.tsx @@ -0,0 +1,99 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import { fireEvent, render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +/* eslint-enable import/no-extraneous-dependencies */ +import React from 'react'; + +import Sorting from '../pages/sorting'; + +describe('Sorting', () => { + it('should sort', () => { + render(); + + const CommaInputs = [ + 'c,a,b', + 'c,a,b', + 'cc,a,bbb', + 'cc,a,bbb', + 'c,a,b', + ]; + const otherSeparatorsInputs = [ + 'c a b', + 'c.a.b', + 'c;a;b', + 'c\na\nb', + ]; + const CommaOutputs = [ + 'a,b,c', + 'c,b,a', + 'a,cc,bbb', + 'bbb,cc,a', + 'b,a,c', + ]; + const otherSeparatorOutputs = [ + 'a b c', + 'a.b.c', + 'a;b;c', + 'a\nb\nc', + ]; + + const SortStyleList = [ + 'ascending', + 'descending', + 'ascending2', + 'descending2', + 'reverse', + ]; + + const SortButton = screen.getByRole('button', { + name: 'Sort', + }) as HTMLButtonElement; + + CommaInputs.forEach((input, index) => { + const inputText = screen.getByLabelText( + 'Input', + ) as HTMLInputElement; + userEvent.type(inputText, input).then(() => { + const sortStyle = screen.getByLabelText( + 'Sort Style', + ) as HTMLInputElement; + fireEvent.change(sortStyle, { + target: { value: SortStyleList[index] }, + }); + userEvent.click(SortButton).then(() => { + const outputText = screen.getByLabelText('Output'); + expect(outputText.innerText).toBe(CommaOutputs[index]); + }); + }); + }); + + const SeparatorsList = ['space', 'dot', 'semicolon', 'lineBreak']; + otherSeparatorsInputs.forEach((input, index) => { + const inputText = screen.getByLabelText( + 'Input', + ) as HTMLInputElement; + userEvent.type(inputText, input).then(() => { + const separator = screen.getByLabelText( + 'Separator', + ) as HTMLInputElement; + fireEvent.change(separator, { + target: { value: SeparatorsList[index] }, + }); + + const sortStyle = screen.getByLabelText( + 'Sort Style', + ) as HTMLInputElement; + fireEvent.change(sortStyle, { + target: { value: SortStyleList[index] }, + }); + + userEvent.click(SortButton).then(() => { + const outputText = screen.getByLabelText('Output'); + expect(outputText.innerText).toBe( + otherSeparatorOutputs[index], + ); + }); + }); + }); + }); +}); diff --git a/pages/sorting.tsx b/pages/sorting.tsx new file mode 100644 index 0000000..ba042a7 --- /dev/null +++ b/pages/sorting.tsx @@ -0,0 +1,251 @@ +import ClearIcon from '@mui/icons-material/Clear'; +import ContentCopyIcon from '@mui/icons-material/ContentCopy'; +import ContentPasteGoIcon from '@mui/icons-material/ContentPasteGo'; +import { Typography } from '@mui/material'; +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import FormControl from '@mui/material/FormControl'; +import InputLabel from '@mui/material/InputLabel'; +import MenuItem from '@mui/material/MenuItem'; +import Select, { SelectChangeEvent } from '@mui/material/Select'; +import TextField from '@mui/material/TextField'; +import React, { useState } from 'react'; + +import Heading from '../components/Heading'; +import Layout from '../components/Layout'; +import Toast, { ToastProps } from '../components/Toast'; +import useLocalState from '../hooks/useLocalState'; +import useSupportsClipboardRead from '../hooks/useSupportsClipboardRead'; + +export default function Sorting() { + const supportsClipboardRead = useSupportsClipboardRead(); + const [inputText, setInputText] = useLocalState({ + key: 'inputTextLocalState', + defaultValue: '', + }); + + const [sortStyle, setSortStyle] = useLocalState({ + key: 'sortStyleLocalState', + defaultValue: 'ascending', + }); + + const [separator, setSeparator] = useLocalState({ + key: 'separatorLocalState', + defaultValue: ',', + }); + + const [outputText, setOutputText] = useLocalState({ + key: 'outputTextLocalState', + defaultValue: '', + }); + + const [toastOpen, setToastOpen] = useState(false); + const [toastMessage, setToastMessage] = useState(''); + const [toastSeverity, setToastSeverity] = + useState('success'); + + const handleSortStyleChange = (event: SelectChangeEvent) => { + setSortStyle(event.target.value); + }; + + const handleSeparatorChange = (event: SelectChangeEvent) => { + setSeparator(event.target.value); + }; + + const handleClear = () => { + setInputText(''); + setOutputText(''); + }; + + const handlePaste = async () => { + const textCopied = await navigator.clipboard.readText(); + setInputText(textCopied); + setOutputText(decodeURIComponent(textCopied)); + }; + + const handleSort = () => { + if (inputText === '') { + setToastMessage('Please enter some text to sort.'); + setToastSeverity('error'); + setToastOpen(true); + return; + } + + if (separator === '') { + setToastMessage('Please enter a separator.'); + setToastSeverity('error'); + setToastOpen(true); + return; + } + + let inputTextArray; + + if (separator === 'lineBreak') { + inputTextArray = inputText.split(/\r\n|\n\r|\n|\r/); + setSeparator('\n'); + } else { + inputTextArray = inputText.split(separator); + } + const outputTextArray = + sortStyle === 'reverse' + ? inputTextArray.reverse() + : inputTextArray.sort((a, b) => { + if (sortStyle === 'ascending') { + return a.localeCompare(b); + } + if (sortStyle === 'descending') { + return b.localeCompare(a); + } + if (sortStyle === 'ascending2') { + if (a.length === b.length) { + return a.localeCompare(b); + } + return a.length - b.length; + } + if (sortStyle === 'descending2') { + if (a.length === b.length) { + return b.localeCompare(a); + } + return b.length - a.length; + } + return 0; + }); + + setOutputText(outputTextArray.join(separator)); + if (separator === '\n') setSeparator('lineBreak'); + }; + + return ( + + Sorting Tool + + Paste or Type an list and select options from the dropdown to + sort + + + + + setInputText(event.target.value)} + multiline + /> + + + {supportsClipboardRead && ( + + )} + + + Sort Style + + + + + Separator + + + + + + + + + + + + + + + setToastOpen(false)} + /> + + ); +} From b4bea74c2b54f231095e09c0f5ccc283d9ac07f4 Mon Sep 17 00:00:00 2001 From: Sidharth Sethi Date: Thu, 6 Oct 2022 23:39:56 +0530 Subject: [PATCH 2/4] Added Icon --- .eslintrc.json | 6 ++++++ data/nav.ts | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/.eslintrc.json b/.eslintrc.json index ad4cd4e..1d77462 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -54,6 +54,12 @@ } }, "rules": { + "prettier/prettier": [ + "error", + { + "endOfLine": "auto" + } + ], "import/extensions": "off", "react/prop-types": "off", "no-plusplus": "off", diff --git a/data/nav.ts b/data/nav.ts index 663d636..490d4c6 100644 --- a/data/nav.ts +++ b/data/nav.ts @@ -6,6 +6,7 @@ import Fingerprint from '@mui/icons-material/Fingerprint'; import HomeIcon from '@mui/icons-material/Home'; import LinkIcon from '@mui/icons-material/Link'; import Looks6 from '@mui/icons-material/Looks6'; +import SortByAlphaIcon from '@mui/icons-material/SortByAlpha'; // Icons Index: https://mui.com/material-ui/material-icons/ @@ -45,6 +46,11 @@ export default [ href: '/url-encode', Icon: LinkIcon, }, + { + title: 'Sorting', + href: '/sorting', + Icon: SortByAlphaIcon, + }, { title: 'HTML', href: '/html', From 4b13c64c34e47dec356c0c1c17576f5d39cbf6ca Mon Sep 17 00:00:00 2001 From: Sidharth Sethi <76687985+TechSpiritSS@users.noreply.github.com> Date: Fri, 7 Oct 2022 01:53:52 +0530 Subject: [PATCH 3/4] fixed eslint issue --- .eslintrc.json | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 1d77462..302e41e 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -54,12 +54,6 @@ } }, "rules": { - "prettier/prettier": [ - "error", - { - "endOfLine": "auto" - } - ], "import/extensions": "off", "react/prop-types": "off", "no-plusplus": "off", @@ -107,4 +101,4 @@ } ] } -} \ No newline at end of file +} From 9bf29811876f5b62aecc13c1a4bd06068f61859a Mon Sep 17 00:00:00 2001 From: Sidharth Sethi Date: Sat, 8 Oct 2022 15:07:19 +0530 Subject: [PATCH 4/4] Fixed New Line issue --- pages/sorting.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pages/sorting.tsx b/pages/sorting.tsx index ba042a7..31511ff 100644 --- a/pages/sorting.tsx +++ b/pages/sorting.tsx @@ -80,9 +80,8 @@ export default function Sorting() { let inputTextArray; - if (separator === 'lineBreak') { + if (separator === 'newLine') { inputTextArray = inputText.split(/\r\n|\n\r|\n|\r/); - setSeparator('\n'); } else { inputTextArray = inputText.split(separator); } @@ -111,8 +110,9 @@ export default function Sorting() { return 0; }); - setOutputText(outputTextArray.join(separator)); - if (separator === '\n') setSeparator('lineBreak'); + if (separator === 'newLine') + setOutputText(outputTextArray.join('\n')); + else setOutputText(outputTextArray.join(separator)); }; return ( @@ -195,7 +195,7 @@ export default function Sorting() { Space ( ) Full Stop (.) Semicolon (;) - New Line + New Line