Open dsebastien opened 1 year ago
Profile/Partials/UpdateProfileInformationForm.tsx:
const [photoPreview, setPhotoPreview] = useState<string | null>(null);
const photoRef = useRef<HTMLInputElement>(null);
const photoInput: any = useRef(null);
...
function selectNewPhoto() {
photoRef.current?.click();
}
function updatePhotoPreview() {
const photo = photoRef.current?.files?.[0];
if (!photo) {
return;
}
form.setData('photo', photo);
const reader = new FileReader();
reader.onload = (e) => {
setPhotoPreview(e.target?.result as string);
};
reader.readAsDataURL(photo);
}
function deletePhoto() {
router.delete(route('current-user-photo.destroy'), {
preserveScroll: true,
onSuccess: () => {
setPhotoPreview(null);
clearPhotoFileInput();
},
});
}
function clearPhotoFileInput() {
if (photoRef.current?.value) {
photoRef.current.value = '';
form.setData('photo', null);
}
}
...
// in form post method:
onSuccess: () => clearPhotoFileInput(),
...
In updateProfileInformation method:
if (photoInput.value) {
form.photo = photoInput.value.files[0];
}
...
...
{/* <!-- Profile Photo --> */}
{page.props.jetstream.managesProfilePhotos ? (
<div className="col-span-6 sm:col-span-4">
{/* <!-- Profile Photo File Input --> */}
<input type="file" className="hidden" ref={photoRef} onChange={updatePhotoPreview} />
<InputLabel htmlFor="photo" value="Photo" />
{photoPreview ? (
// <!-- New Profile Photo Preview -->
<div className="mt-2">
<span
className="block rounded-full w-20 h-20"
style={{
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center center',
backgroundImage: `url('${photoPreview}')`,
}}
></span>
</div>
) : (
// <!-- Current Profile Photo -->
<div className="mt-2">
<img src={user.profile_photo_url} alt={user.name} className="rounded-full h-20 w-20 object-cover" />
</div>
)}
<SecondaryButton className="mt-2 mr-2" type="button" onClick={selectNewPhoto}>
Select A New Photo
</SecondaryButton>
{user.profile_photo_path ? (
<SecondaryButton type="button" className="mt-2" onClick={deletePhoto}>
Remove Photo
</SecondaryButton>
) : null}
<InputError message={form.errors.photo} className="mt-2" />
</div>
) : null}
In Profile\Partials\UpdateProfileInformationForm, vue version:
<!-- Profile Photo -->
<div v-if="$page.props.jetstream.managesProfilePhotos" class="col-span-6 sm:col-span-4">
<!-- Profile Photo File Input -->
<input id="photo" ref="photoInput" type="file" class="hidden" @change="updatePhotoPreview" />
<InputLabel for="photo" value="Photo" />
<!-- Current Profile Photo -->
<div v-show="!photoPreview" class="mt-2">
<img :src="user.profile_photo_url" :alt="user.name" class="rounded-full h-20 w-20 object-cover" />
</div>
<!-- New Profile Photo Preview -->
<div v-show="photoPreview" class="mt-2">
<span
class="block rounded-full w-20 h-20 bg-cover bg-no-repeat bg-center"
:style="'background-image: url(\'' + photoPreview + '\');'"
/>
</div>
<SecondaryButton class="mt-2 me-2" type="button" @click.prevent="selectNewPhoto"> Select A New Photo </SecondaryButton>
<SecondaryButton v-if="user.profile_photo_path" type="button" class="mt-2" @click.prevent="deletePhoto">
Remove Photo
</SecondaryButton>
<InputError :message="form.errors.photo" class="mt-2" />
</div>
Another version:
{jetstream.managesProfilePhotos && (
<div className="col-span-6 sm:col-span-4">
<input id="photo" ref={photoInput} type="file" className="hidden" onChange={updatePhotoPreview} />
<InputLabel htmlFor="photo" value="Photo" />
{!photoPreview ? (
<div className="mt-2">
<img src={user.profile_photo_url} alt={user.name} className="object-cover w-20 h-20 rounded-full" />
</div>
) : (
<div className="mt-2">
<span
className="block w-20 h-20 bg-center bg-no-repeat bg-cover rounded-full"
style={{
backgroundImage: `url('${photoPreview}')`,
}}
/>
</div>
)}
<SecondaryButton className="mt-2 me-2" type="button" onClick={selectNewPhoto}>
Select A New Photo
</SecondaryButton>
{user.profile_photo_path && (
<SecondaryButton type="button" className="mt-2" onClick={deletePhoto}>
Remove Photo
</SecondaryButton>
)}
<InputError message={form.errors.photo} className="mt-2" />
</div>
)}
Make sure to protect against malicious image uploads: https://medium.com/@dsjayamal/8-security-best-practices-in-laravel-ad7513798cfb
To store user pictures:
page.props.jetstream.managesProfilePhotos page.props.auth.user.profile_photo_url