-
Notifications
You must be signed in to change notification settings - Fork 1
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/upgradefileupload #1633
Feat/upgradefileupload #1633
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -3,31 +3,46 @@ import classNames from 'classnames'; | |||||
import { type ChangeEvent, type ReactNode, useEffect, useState } from 'react'; | ||||||
import { useTranslation } from 'react-i18next'; | ||||||
import { KEY } from '~/i18n/constants'; | ||||||
import { getFileNameFromUrl, isFileImage } from '~/utils'; | ||||||
import { Link } from '../Link'; | ||||||
import { TimeDisplay } from '../TimeDisplay'; | ||||||
import styles from './InputFile.module.scss'; | ||||||
|
||||||
export type InputFileType = 'image' | 'pdf'; | ||||||
export type InputFileType = 'image' | 'pdf' | 'any'; | ||||||
|
||||||
export type InputFileProps = { | ||||||
fileType: InputFileType; | ||||||
fileType?: InputFileType; | ||||||
label?: ReactNode; | ||||||
existing_url?: string; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
og for resten seff. |
||||||
error?: boolean | string; | ||||||
onSelected: (file: File) => void; | ||||||
acceptedTypes?: string; | ||||||
onSelected?: (file: File) => void; | ||||||
}; | ||||||
|
||||||
export function InputFile({ fileType, label, error = false, onSelected }: InputFileProps) { | ||||||
export function InputFile({ | ||||||
fileType = 'any', | ||||||
acceptedTypes, | ||||||
label, | ||||||
existing_url, | ||||||
error = false, | ||||||
onSelected, | ||||||
}: InputFileProps) { | ||||||
const { t } = useTranslation(); | ||||||
const [selectedFile, setSelectedFile] = useState<File | undefined>(undefined); | ||||||
const [preview, setPreview] = useState<string | undefined>(undefined); | ||||||
const [isImage, setIsImage] = useState<boolean>(false); | ||||||
|
||||||
function handleOnChange(e?: ChangeEvent<HTMLInputElement>) { | ||||||
if (e === undefined) return; | ||||||
if (e === undefined || onSelected === undefined) return; | ||||||
if (!e.target.files || e.target.files.length === 0) { | ||||||
setSelectedFile(undefined); | ||||||
} else { | ||||||
setSelectedFile(e.target.files?.[0]); | ||||||
if (e.target.files?.[0] !== undefined) { | ||||||
onSelected(e.target.files?.[0]); | ||||||
setIsImage(isFileImage(e.target.files?.[0].name)); | ||||||
} else { | ||||||
setIsImage(false); | ||||||
} | ||||||
} | ||||||
} | ||||||
|
@@ -45,23 +60,31 @@ export function InputFile({ fileType, label, error = false, onSelected }: InputF | |||||
return () => URL.revokeObjectURL(objectUrl); | ||||||
}, [selectedFile]); | ||||||
|
||||||
useEffect(() => { | ||||||
if (existing_url && isFileImage(existing_url)) { | ||||||
setIsImage(true); | ||||||
setPreview(existing_url); | ||||||
} | ||||||
}, [existing_url]); | ||||||
|
||||||
function acceptTypes() { | ||||||
switch (fileType) { | ||||||
case 'image': | ||||||
return 'image/*'; | ||||||
case 'pdf': | ||||||
return 'application/pdf'; | ||||||
if (fileType === 'any' && !acceptedTypes) { | ||||||
return '*'; | ||||||
} | ||||||
return '*'; | ||||||
let types = acceptedTypes ? acceptedTypes : ''; | ||||||
if (fileType === 'image') types += ', image/*'; | ||||||
if (fileType === 'pdf') types += ', application/pdf'; | ||||||
return types; | ||||||
} | ||||||
|
||||||
const icons: Record<InputFileType, string> = { | ||||||
image: 'mdi:image', | ||||||
pdf: 'mdi:file', | ||||||
any: 'mdi:file', | ||||||
}; | ||||||
|
||||||
const horizontalPreview = fileType === 'pdf'; | ||||||
const typePreviewClass = `preview_${fileType.toLowerCase()}`; | ||||||
const typePreviewClass = `preview_${fileType?.toLowerCase()}`; | ||||||
const fileSizeMb = ((selectedFile?.size ?? 0) / 1024 / 1024).toFixed(2); | ||||||
const isError = error !== false; | ||||||
|
||||||
|
@@ -79,28 +102,30 @@ export function InputFile({ fileType, label, error = false, onSelected }: InputF | |||||
<Icon icon={icons[fileType] ?? ''} /> | ||||||
{t(KEY.inputfile_choose_a_file)} | ||||||
</div> | ||||||
{fileType === 'image' && ( | ||||||
{existing_url && !selectedFile ? ( | ||||||
<Link className={styles.title} url={existing_url} target="external"> | ||||||
{getFileNameFromUrl(existing_url)} | ||||||
</Link> | ||||||
) : ( | ||||||
<span className={styles.title}>{selectedFile?.name ?? t(KEY.inputfile_no_file_selected)}</span> | ||||||
)} | ||||||
</div> | ||||||
|
||||||
{/* File Preview */} | ||||||
<div className={classNames(styles.selected_container, fileType === 'pdf' && styles.pdf)}> | ||||||
{/* PDF shows additional information */} | ||||||
{fileType === 'pdf' && ( | ||||||
<div className={styles.preview_meta}> | ||||||
<p className={styles.title}>{selectedFile?.name ?? t(KEY.inputfile_no_file_selected)}</p> | ||||||
<p> | ||||||
<TimeDisplay timestamp={new Date(selectedFile?.lastModified ?? 0)} /> | ||||||
</p> | ||||||
<p>{fileSizeMb} MB</p> | ||||||
</div> | ||||||
)} | ||||||
{/* Image/pdf preview. Shows empty preview for pdf type */} | ||||||
{(fileType === 'pdf' || preview) && ( | ||||||
<div className={classNames(styles.preview_container, styles[typePreviewClass])}> | ||||||
{preview && <img className={styles.preview} src={preview} alt="Preview" />} | ||||||
</div> | ||||||
<div className={styles.selected_container}> | ||||||
{preview && ( | ||||||
<> | ||||||
<div className={styles.preview_meta}> | ||||||
<p> | ||||||
<TimeDisplay timestamp={new Date(selectedFile?.lastModified ?? 0)} /> | ||||||
</p> | ||||||
<p>{fileSizeMb} MB</p> | ||||||
</div> | ||||||
{isImage && ( | ||||||
<div className={classNames(styles.preview_container, styles[typePreviewClass])}> | ||||||
{preview && <img className={styles.preview} src={preview} alt="Preview" />} | ||||||
</div> | ||||||
)} | ||||||
</> | ||||||
)} | ||||||
</div> | ||||||
</label> | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -103,6 +103,7 @@ export type SamfFormFieldType = | |
| 'date_time' | ||
| 'date' | ||
| 'time' | ||
| 'file' | ||
| 'upload_image' | ||
| 'upload_pdf' | ||
| 'phonenumber'; | ||
|
@@ -132,6 +133,7 @@ export const SamfFormGenerators: Record<SamfFormFieldType, GeneratorFunction<any | |
date_time: makeStandardInputFunction<Date>('datetime-local'), | ||
date: makeStandardInputFunction<Date>('date'), | ||
time: makeStandardInputFunction<Date>('time'), | ||
file: makeFilePickerFunction('any'), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Vi bruker ikke Samfform lengre btw. Gått over til ReactHook-form |
||
upload_image: makeFilePickerFunction('image'), | ||
upload_pdf: makeFilePickerFunction('pdf'), | ||
phonenumber: makePhoneNumberInput, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -209,6 +209,11 @@ export function RecruitmentApplicationFormPage() { | |
> | ||
<h2 className={styles.label}>{t(KEY.recruitment_application)}:</h2> | ||
<SamfFormField field="application_text" type="text_long" />{' '} | ||
<SamfFormField | ||
field="file" | ||
type="file" | ||
props={{ existing_url: 'http://localhost:3000/src/assets/logos/uka.png' }} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. trengs det en default her? |
||
/> | ||
Comment on lines
+212
to
+216
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dette bør vel kun rendres hvis stillingen har mulighet for fil opplasting. Vi bruker ikke Samfform lengre btw. Gått over til ReactHook-form |
||
</SamfForm> | ||
) : ( | ||
<div> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Behold kommentarene som var på line 87, 89 og 99