mirror of
https://github.com/Qortal/chrome-extension.git
synced 2025-02-11 17:55:49 +00:00
Merge pull request #3 from Skidragon/view-plain-text-password-field
Toggle Plain Text on Password Fields
This commit is contained in:
commit
0e2816f57e
1655
package-lock.json
generated
1655
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@ -7,12 +7,16 @@
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview"
|
||||
"preview": "vite preview",
|
||||
"test": "vitest",
|
||||
"coverage": "vitest run --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.11.4",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@mui/material": "^5.15.14",
|
||||
"@testing-library/jest-dom": "^6.4.6",
|
||||
"@testing-library/user-event": "^14.5.2",
|
||||
"@types/chrome": "^0.0.263",
|
||||
"asmcrypto.js": "2.3.2",
|
||||
"bcryptjs": "2.4.3",
|
||||
@ -25,6 +29,8 @@
|
||||
"react-dropzone": "^14.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/dom": "^10.3.0",
|
||||
"@testing-library/react": "^16.0.0",
|
||||
"@types/react": "^18.2.64",
|
||||
"@types/react-copy-to-clipboard": "^5.0.7",
|
||||
"@types/react-dom": "^18.2.21",
|
||||
@ -35,6 +41,7 @@
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.5",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^5.1.6"
|
||||
"vite": "^5.1.6",
|
||||
"vitest": "^1.6.0"
|
||||
}
|
||||
}
|
||||
|
16
src/App.tsx
16
src/App.tsx
@ -41,6 +41,7 @@ import {
|
||||
} from "./App-styles";
|
||||
import { Spacer } from "./common/Spacer";
|
||||
import { Loader } from "./components/Loader";
|
||||
import { PasswordField } from "./components";
|
||||
|
||||
type extStates =
|
||||
| "not-authenticated"
|
||||
@ -741,8 +742,7 @@ function App() {
|
||||
Confirm Wallet Password
|
||||
</CustomLabel>
|
||||
<Spacer height="5px" />
|
||||
<CustomInput
|
||||
type="password"
|
||||
<PasswordField
|
||||
id="standard-adornment-password"
|
||||
value={paymentPassword}
|
||||
onChange={(e) => setPaymentPassword(e.target.value)}
|
||||
@ -808,8 +808,7 @@ function App() {
|
||||
Confirm Wallet Password
|
||||
</CustomLabel>
|
||||
<Spacer height="5px" />
|
||||
<CustomInput
|
||||
type="password"
|
||||
<PasswordField
|
||||
id="standard-adornment-password"
|
||||
value={paymentPassword}
|
||||
onChange={(e) => setPaymentPassword(e.target.value)}
|
||||
@ -1000,8 +999,7 @@ function App() {
|
||||
Confirm Wallet Password
|
||||
</CustomLabel>
|
||||
<Spacer height="5px" />
|
||||
<CustomInput
|
||||
type="password"
|
||||
<PasswordField
|
||||
id="standard-adornment-password"
|
||||
value={walletToBeDownloadedPassword}
|
||||
onChange={(e) =>
|
||||
@ -1073,8 +1071,7 @@ function App() {
|
||||
Wallet Password
|
||||
</CustomLabel>
|
||||
<Spacer height="5px" />
|
||||
<CustomInput
|
||||
type="password"
|
||||
<PasswordField
|
||||
id="standard-adornment-password"
|
||||
value={walletToBeDownloadedPassword}
|
||||
onChange={(e) =>
|
||||
@ -1086,8 +1083,7 @@ function App() {
|
||||
Confirm Wallet Password
|
||||
</CustomLabel>
|
||||
<Spacer height="5px" />
|
||||
<CustomInput
|
||||
type="password"
|
||||
<PasswordField
|
||||
id="standard-adornment-password"
|
||||
value={walletToBeDownloadedPasswordConfirm}
|
||||
onChange={(e) =>
|
||||
|
28
src/components/PasswordField/PasswordField.spec.tsx
Normal file
28
src/components/PasswordField/PasswordField.spec.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import {
|
||||
describe,
|
||||
expect,
|
||||
test
|
||||
} from 'vitest';
|
||||
import { render } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import {
|
||||
PasswordField
|
||||
} from './PasswordField'
|
||||
|
||||
|
||||
describe('PasswordField', () => {
|
||||
test('it renders', () => {
|
||||
const { queryByTestId } = render(<PasswordField data-testid="test-id" value="test-value" />)
|
||||
expect(queryByTestId('test-id')).toBeTruthy()
|
||||
})
|
||||
|
||||
test('User can toggle between plain text view and password view', async () => {
|
||||
const { getByTestId } = render(<PasswordField data-testid="test-id" value="test-value" />)
|
||||
const user = userEvent.setup();
|
||||
expect(getByTestId("password-text-indicator").textContent).toBe('👁️🗨️');
|
||||
await user.click(getByTestId('toggle-view-password-btn'));
|
||||
expect(getByTestId("plain-text-indicator").textContent).toBe('👁️');
|
||||
await user.click(getByTestId('toggle-view-password-btn'));
|
||||
expect(getByTestId("password-text-indicator").textContent).toBe('👁️🗨️');
|
||||
})
|
||||
})
|
61
src/components/PasswordField/PasswordField.tsx
Normal file
61
src/components/PasswordField/PasswordField.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
import { Button, InputAdornment, TextField, TextFieldProps, styled } from "@mui/material";
|
||||
import { useState } from 'react'
|
||||
|
||||
export const CustomInput = styled(TextField)({
|
||||
width: "183px", // Adjust the width as needed
|
||||
borderRadius: "5px",
|
||||
// backgroundColor: "rgba(30, 30, 32, 1)",
|
||||
outline: "none",
|
||||
input: {
|
||||
fontSize: 10,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: 400,
|
||||
color: "white",
|
||||
"&::placeholder": {
|
||||
fontSize: 16,
|
||||
color: "rgba(255, 255, 255, 0.2)",
|
||||
},
|
||||
outline: "none",
|
||||
padding: "10px",
|
||||
},
|
||||
"& .MuiOutlinedInput-root": {
|
||||
"& fieldset": {
|
||||
border: '0.5px solid rgba(255, 255, 255, 0.5)',
|
||||
},
|
||||
"&:hover fieldset": {
|
||||
border: '0.5px solid rgba(255, 255, 255, 0.5)',
|
||||
},
|
||||
"&.Mui-focused fieldset": {
|
||||
border: '0.5px solid rgba(255, 255, 255, 0.5)',
|
||||
},
|
||||
},
|
||||
"& .MuiInput-underline:before": {
|
||||
borderBottom: "none",
|
||||
},
|
||||
"& .MuiInput-underline:hover:not(.Mui-disabled):before": {
|
||||
borderBottom: "none",
|
||||
},
|
||||
"& .MuiInput-underline:after": {
|
||||
borderBottom: "none",
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
export const PasswordField: React.FunctionComponent<TextFieldProps> = ({ ...props }) => {
|
||||
const [canViewPassword, setCanViewPassword] = useState(false);
|
||||
return (
|
||||
<CustomInput
|
||||
type={canViewPassword ? 'text' : 'password'}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end" data-testid="toggle-view-password-btn" onClick={() => {
|
||||
setCanViewPassword((prevState) => !prevState)
|
||||
}}>
|
||||
{canViewPassword ? <Button data-testid="plain-text-indicator" sx={{ minWidth: 0, p: 0 }}>👁️</Button> : <Button data-testid="password-text-indicator" sx={{ minWidth: 0, p: 0 }}>👁️🗨️</Button>}
|
||||
</InputAdornment>
|
||||
)
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
1
src/components/index.ts
Normal file
1
src/components/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './PasswordField/PasswordField';
|
1
src/test/setup.ts
Normal file
1
src/test/setup.ts
Normal file
@ -0,0 +1 @@
|
||||
import '@testing-library/jest-dom'
|
@ -1,9 +1,15 @@
|
||||
/// <reference types="vitest" />
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
// Import path module for resolving file paths
|
||||
import { resolve } from 'path';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
environment: 'jsdom',
|
||||
globals: true,
|
||||
setupFiles: ['./src/test/setup.ts']
|
||||
},
|
||||
plugins: [react()],
|
||||
build: {
|
||||
rollupOptions: {
|
||||
|
Loading…
x
Reference in New Issue
Block a user