extract component
This commit is contained in:
parent
cd2f977bff
commit
59f8f33df7
46
resources/assets/src/components/FileInput.tsx
Normal file
46
resources/assets/src/components/FileInput.tsx
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import React, { useRef } from 'react'
|
||||||
|
import { t } from '@/scripts/i18n'
|
||||||
|
import styles from './FileInput.module.scss'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
file: File | null
|
||||||
|
accept?: string
|
||||||
|
onChange(event: React.ChangeEvent<HTMLInputElement>): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const FileInput: React.FC<Props> = props => {
|
||||||
|
const ref = useRef<HTMLInputElement>(null)
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
ref.current!.click()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="select-file">{t('skinlib.upload.select-file')}</label>
|
||||||
|
<div className="input-group">
|
||||||
|
<div className="custom-file">
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
className="custom-file-input"
|
||||||
|
id="select-file"
|
||||||
|
accept={props.accept}
|
||||||
|
title={t('skinlib.upload.select-file')}
|
||||||
|
ref={ref}
|
||||||
|
onChange={props.onChange}
|
||||||
|
/>
|
||||||
|
<label className={`custom-file-label ${styles.label}`}>
|
||||||
|
{props.file?.name}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="input-group-append">
|
||||||
|
<button className="btn btn-default" onClick={handleClick}>
|
||||||
|
{t('skinlib.upload.select-file')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FileInput
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState, useEffect, useRef } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import { hot } from 'react-hot-loader/root'
|
import { hot } from 'react-hot-loader/root'
|
||||||
import { t } from '@/scripts/i18n'
|
import { t } from '@/scripts/i18n'
|
||||||
|
|
@ -7,8 +7,8 @@ import * as fetch from '@/scripts/net'
|
||||||
import { showModal, toast } from '@/scripts/notify'
|
import { showModal, toast } from '@/scripts/notify'
|
||||||
import { isAlex } from '@/scripts/textureUtils'
|
import { isAlex } from '@/scripts/textureUtils'
|
||||||
import { TextureType } from '@/scripts/types'
|
import { TextureType } from '@/scripts/types'
|
||||||
|
import FileInput from '@/components/FileInput'
|
||||||
import ViewerSkeleton from '@/components/ViewerSkeleton'
|
import ViewerSkeleton from '@/components/ViewerSkeleton'
|
||||||
import styles from './styles.module.scss'
|
|
||||||
|
|
||||||
const Previewer = React.lazy(() => import('@/components/Viewer'))
|
const Previewer = React.lazy(() => import('@/components/Viewer'))
|
||||||
|
|
||||||
|
|
@ -21,7 +21,6 @@ const Upload: React.FC = () => {
|
||||||
const [isUploading, setIsUploading] = useState(false)
|
const [isUploading, setIsUploading] = useState(false)
|
||||||
const [file, setFile] = useState<File | null>(null)
|
const [file, setFile] = useState<File | null>(null)
|
||||||
const [texture, setTexture] = useState('')
|
const [texture, setTexture] = useState('')
|
||||||
const fileInput = useRef<HTMLInputElement>(null)
|
|
||||||
const nameRule = useBlessingExtra<string>('rule')
|
const nameRule = useBlessingExtra<string>('rule')
|
||||||
const contentPolicy = useBlessingExtra<string>('contentPolicy')
|
const contentPolicy = useBlessingExtra<string>('contentPolicy')
|
||||||
const privacyNotice = useBlessingExtra<string>('privacyNotice')
|
const privacyNotice = useBlessingExtra<string>('privacyNotice')
|
||||||
|
|
@ -51,11 +50,7 @@ const Upload: React.FC = () => {
|
||||||
setIsPrivate(event.target.checked)
|
setIsPrivate(event.target.checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
const invokeSelectFile = () => {
|
const handleFileChange = async (
|
||||||
fileInput.current!.click()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSelectFile = async (
|
|
||||||
event: React.ChangeEvent<HTMLInputElement>,
|
event: React.ChangeEvent<HTMLInputElement>,
|
||||||
) => {
|
) => {
|
||||||
const files = event.target.files!
|
const files = event.target.files!
|
||||||
|
|
@ -177,32 +172,11 @@ const Upload: React.FC = () => {
|
||||||
{t('general.cape')}
|
{t('general.cape')}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-group">
|
<FileInput
|
||||||
<label htmlFor="select-file">
|
file={file}
|
||||||
{t('skinlib.upload.select-file')}
|
accept="image/png, image/x-png"
|
||||||
</label>
|
onChange={handleFileChange}
|
||||||
<div className="input-group">
|
/>
|
||||||
<div className="custom-file">
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
className="custom-file-input"
|
|
||||||
id="select-file"
|
|
||||||
accept="image/png, image/x-png"
|
|
||||||
title={t('skinlib.upload.select-file')}
|
|
||||||
ref={fileInput}
|
|
||||||
onChange={handleSelectFile}
|
|
||||||
/>
|
|
||||||
<label className={`custom-file-label ${styles.label}`}>
|
|
||||||
{file?.name}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div className="input-group-append">
|
|
||||||
<button className="btn btn-default" onClick={invokeSelectFile}>
|
|
||||||
{t('skinlib.upload.select-file')}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{contentPolicy && (
|
{contentPolicy && (
|
||||||
<div
|
<div
|
||||||
25
resources/assets/tests/components/FileInput.test.tsx
Normal file
25
resources/assets/tests/components/FileInput.test.tsx
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { render, fireEvent } from '@testing-library/react'
|
||||||
|
import { t } from '@/scripts/i18n'
|
||||||
|
import FileInput from '@/components/FileInput'
|
||||||
|
|
||||||
|
test('click to select file', () => {
|
||||||
|
const { getAllByText } = render(<FileInput file={null} onChange={() => {}} />)
|
||||||
|
|
||||||
|
fireEvent.click(getAllByText(t('skinlib.upload.select-file'))[1])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('display file name', () => {
|
||||||
|
const file = new File([], 'f.txt')
|
||||||
|
const { queryByText } = render(<FileInput file={file} onChange={() => {}} />)
|
||||||
|
expect(queryByText('f.txt')).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('input file', () => {
|
||||||
|
const mock = jest.fn()
|
||||||
|
|
||||||
|
const { getByLabelText } = render(<FileInput file={null} onChange={mock} />)
|
||||||
|
fireEvent.change(getByLabelText(t('skinlib.upload.select-file')))
|
||||||
|
|
||||||
|
expect(mock).toBeCalled()
|
||||||
|
})
|
||||||
|
|
@ -60,12 +60,6 @@ test('award notice', () => {
|
||||||
).not.toBeInTheDocument()
|
).not.toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('invoke selecting file', () => {
|
|
||||||
const { getAllByText } = render(<Upload />)
|
|
||||||
|
|
||||||
fireEvent.click(getAllByText(t('skinlib.upload.select-file'))[1])
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('input file', () => {
|
describe('input file', () => {
|
||||||
it('cancelled', () => {
|
it('cancelled', () => {
|
||||||
const { getByTitle } = render(<Upload />)
|
const { getByTitle } = render(<Upload />)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user