Skip to content

Commit

Permalink
refactor: migrate edit-profil-navigate to use tool-avatar-select
Browse files Browse the repository at this point in the history
  • Loading branch information
valeriansaliou committed Jun 23, 2024
1 parent 6a8a524 commit 1b5a411
Showing 1 changed file with 17 additions and 226 deletions.
243 changes: 17 additions & 226 deletions src/components/popups/sidebar/EditProfileNavigate.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,38 +11,11 @@
<template lang="pug">
.p-edit-profile-navigate
.p-edit-profile-navigate__identity
div(
:class=`[
"p-edit-profile-navigate__identity-avatar",
{
"p-edit-profile-navigate__identity-avatar--locked": pending || avatarFileLoading
}
]`
tool-avatar-select(
@update="onAvatarUpdate"
:jid="jid"
:pending="pending"
)
base-avatar(
:jid="jid"
:data-url="avatarUpdate ? avatarUpdate.dataUrl : null"
size="96px"
shadow="light"
class="p-edit-profile-navigate__identity-avatar-image"
square
)

span.p-edit-profile-navigate__identity-avatar-file
input.p-edit-profile-navigate__identity-avatar-input(
@change.prevent="onAvatarFileChange",
:accept="avatarAcceptTypes"
type="file",
id="avatar_file",
tabindex="-1"
)

label.p-edit-profile-navigate__identity-avatar-edit(
for="avatar_file"
)
span.p-edit-profile-navigate__identity-avatar-edit-inner
span.p-edit-profile-navigate__identity-avatar-edit-text.u-bold
| Edit

p.p-edit-profile-navigate__identity-name.u-medium
template(
Expand Down Expand Up @@ -74,37 +47,26 @@
// NPM
import { PropType } from "vue";
import { JID } from "@prose-im/prose-sdk-js";
import Latin1 from "crypto-js/enc-latin1";
import Base64 from "crypto-js/enc-base64";
import { readAndCompressImage } from "browser-image-resizer";

// PROJECT: COMPONENTS
import BaseAlert from "@/components/base/BaseAlert.vue";
import { Section as NavigateSection } from "@/components/base/BaseNavigate.vue";
import {
default as ToolAvatarSelect,
Update as ToolAvatarUpdate
} from "@/components/tool/ToolAvatarSelect.vue";

// PROJECT: STORES
import Store from "@/store";

// INTERFACES
export interface StateAvatarUpdate {
binary: string;
base64: string;
dataUrl: string;
type: string;
bytes: number;
}

// CONSTANTS
const AVATAR_MIME_TYPES = ["image/jpeg", "image/png", "image/gif"];
const AVATAR_EXTENSIONS = ["JPG", "PNG", "GIF"];

const AVATAR_CONVERT_MIME = "image/jpeg";
const AVATAR_COMPRESS_QUALITY = 0.94;
const AVATAR_SIZE_MAXIMUM = 400;
// TYPES
export type StateAvatarUpdate = ToolAvatarUpdate;

export default {
name: "EditProfileEncryptionDeviceOther",

components: { ToolAvatarSelect },

props: {
jid: {
type: Object as PropType<JID>,
Expand Down Expand Up @@ -137,18 +99,11 @@ export default {
return {
// --> STATE <--

section: this.sectionInitial || null,

avatarFileLoading: false,
avatarUpdate: null as StateAvatarUpdate | null
section: this.sectionInitial || null
};
},

computed: {
avatarAcceptTypes(): string {
return AVATAR_MIME_TYPES.join(",");
},

selfName(): string {
return Store.$account.getInformationName();
},
Expand All @@ -159,92 +114,12 @@ export default {
},

methods: {
// --> HELPERS <--

async readAvatarFile(avatarFile: File): Promise<StateAvatarUpdate> {
// #1. Read and normalize image
const avatarBlob = await readAndCompressImage(avatarFile, {
quality: AVATAR_COMPRESS_QUALITY,
maxWidth: AVATAR_SIZE_MAXIMUM,
maxHeight: AVATAR_SIZE_MAXIMUM,
mimeType: AVATAR_CONVERT_MIME
});

// #2. Convert image file blob to Base64
const avatarBinary: string | ArrayBuffer | null = await new Promise(
resolve => {
const reader = new FileReader();

reader.readAsBinaryString(avatarBlob);

reader.onload = () => resolve(reader.result);
reader.onerror = () => resolve(null);
}
);

// #3. Ensure that avatar is defined (and return format is 'string')
if (avatarBinary !== null && typeof avatarBinary === "string") {
// Acquire avatar data from binary
const avatarData = Base64.stringify(Latin1.parse(avatarBinary));
const avatarDataUrl = `data:${avatarBlob.type};base64,${avatarData}`;

return {
binary: avatarBinary,
base64: avatarData,
dataUrl: avatarDataUrl,
type: avatarBlob.type,
bytes: avatarBlob.size
};
}

throw new Error("Could not load avatar");
},

// --> EVENT LISTENERS <--

async onAvatarFileChange(event: InputEvent): Promise<void> {
const target = (event.target as HTMLInputElement) || null;

if (
target?.files &&
target?.files.length > 0 &&
this.avatarFileLoading !== true
) {
const avatarFile: File = target.files[0];

if (AVATAR_MIME_TYPES.includes(avatarFile.type) === true) {
// Mark as loading
this.avatarFileLoading = true;

// Acquire avatar data
try {
const avatarUpdate = await this.readAvatarFile(avatarFile);

this.$emit("avatar", avatarUpdate);

this.avatarUpdate = avatarUpdate;

BaseAlert.info("Avatar changed", "Save your profile to submit it!");
} catch (error) {
this.$log.error("Error loading avatar file", error);

BaseAlert.warning(
"Cannot load this file",
"Image file seems to be empty"
);
}

// Mark as non-loading
this.avatarFileLoading = false;
} else {
BaseAlert.warning(
"Cannot use this file",
`Accepted files: ${AVATAR_EXTENSIONS.join(", ")}`
);
}
} else {
BaseAlert.error("Cannot load avatar", "No file was selected!");
}
async onAvatarUpdate(avatarUpdate: ToolAvatarUpdate): Promise<void> {
this.$emit("avatar", avatarUpdate);

BaseAlert.info("Avatar changed", "Save your profile to submit it!");
},

onSectionsNavigate(sectionId: string): void {
Expand All @@ -267,90 +142,6 @@ $c: ".p-edit-profile-navigate";
#{$c}__identity {
text-align: center;

#{$c}__identity-avatar {
line-height: 0;
overflow: hidden;
display: inline-block;
position: relative;
border-radius: 12px;

&:hover {
#{$c}__identity-avatar-edit {
#{$c}__identity-avatar-edit-inner {
visibility: visible;
opacity: 1;
}
}
}

&:active {
#{$c}__identity-avatar-edit {
#{$c}__identity-avatar-edit-inner {
#{$c}__identity-avatar-edit-text {
transform: scale(0.96);
}
}
}
}

&--locked {
pointer-events: none;
}

#{$c}__identity-avatar-image {
position: relative;
z-index: 1;
}

#{$c}__identity-avatar-file {
overflow: hidden;
position: absolute;
inset: 0;
z-index: -1;

#{$c}__identity-avatar-input {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
display: block;
opacity: 0;
}
}

#{$c}__identity-avatar-edit {
cursor: pointer;
position: absolute;
inset: 0;
z-index: 2;

#{$c}__identity-avatar-edit-inner {
background-image: linear-gradient(
180deg,
rgba(var(--color-black), 0) 0%,
rgba(var(--color-black), 0.6) 100%
);
padding-block-start: 14px;
padding-block-end: 10px;
position: absolute;
inset-inline: 0;
inset-block-end: 0;
visibility: hidden;
opacity: 0;
transition: opacity 100ms linear;

#{$c}__identity-avatar-edit-text {
color: rgb(var(--color-text-reverse));
font-size: 12.5px;
line-height: 14px;
text-transform: lowercase;
display: inline-block;
transition: transform 100ms linear;
}
}
}
}

#{$c}__identity-name {
color: rgb(var(--color-text-primary));
font-size: 15.5px;
Expand Down

0 comments on commit 1b5a411

Please sign in to comment.