Account.svelte 4.48 KB
Newer Older
1
2
3
4
5
6
7
8
<script lang="ts">
	import toast from 'svelte-french-toast';
	import { onMount } from 'svelte';

	import { user } from '$lib/stores';
	import { updateUserProfile } from '$lib/apis/auths';

	import UpdatePassword from './Account/UpdatePassword.svelte';
9
	import { getGravatarUrl } from '$lib/apis/utils';
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

	export let saveHandler: Function;

	let profileImageUrl = '';
	let name = '';

	const submitHandler = async () => {
		const updatedUser = await updateUserProfile(localStorage.token, name, profileImageUrl).catch(
			(error) => {
				toast.error(error);
			}
		);

		if (updatedUser) {
			await user.set(updatedUser);
			return true;
		}
		return false;
	};

	onMount(() => {
		name = $user.name;
		profileImageUrl = $user.profile_image_url;
	});
</script>

<div class="flex flex-col h-full justify-between text-sm">
	<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80">
		<input
			id="profile-image-input"
			type="file"
			hidden
			accept="image/*"
			on:change={(e) => {
				const files = e?.target?.files ?? [];
				let reader = new FileReader();
				reader.onload = (event) => {
					let originalImageUrl = `${event.target.result}`;

					const img = new Image();
					img.src = originalImageUrl;

					img.onload = function () {
						const canvas = document.createElement('canvas');
						const ctx = canvas.getContext('2d');

						// Calculate the aspect ratio of the image
						const aspectRatio = img.width / img.height;

						// Calculate the new width and height to fit within 100x100
						let newWidth, newHeight;
						if (aspectRatio > 1) {
							newWidth = 100 * aspectRatio;
							newHeight = 100;
						} else {
							newWidth = 100;
							newHeight = 100 / aspectRatio;
						}

						// Set the canvas size
						canvas.width = 100;
						canvas.height = 100;

						// Calculate the position to center the image
						const offsetX = (100 - newWidth) / 2;
						const offsetY = (100 - newHeight) / 2;

						// Draw the image on the canvas
						ctx.drawImage(img, offsetX, offsetY, newWidth, newHeight);

						// Get the base64 representation of the compressed image
						const compressedSrc = canvas.toDataURL('image/jpeg');

						// Display the compressed image
						profileImageUrl = compressedSrc;

						e.target.files = null;
					};
				};

				if (
					files.length > 0 &&
					['image/gif', 'image/jpeg', 'image/png'].includes(files[0]['type'])
				) {
					reader.readAsDataURL(files[0]);
				}
			}}
		/>

Timothy J. Baek's avatar
Timothy J. Baek committed
99
		<div class=" mb-2.5 text-sm font-medium">Profile</div>
100
101

		<div class="flex space-x-5">
102
103
104
105
106
107
108
109
			<div class="flex flex-col">
				<div class="self-center">
					<button
						class="relative rounded-full dark:bg-gray-700"
						type="button"
						on:click={() => {
							document.getElementById('profile-image-input')?.click();
						}}
110
					>
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
						<img
							src={profileImageUrl !== '' ? profileImageUrl : '/user.png'}
							alt="profile"
							class=" rounded-full w-16 h-16 object-cover"
						/>

						<div
							class="absolute flex justify-center rounded-full bottom-0 left-0 right-0 top-0 h-full w-full overflow-hidden bg-gray-700 bg-fixed opacity-0 transition duration-300 ease-in-out hover:opacity-50"
						>
							<div class="my-auto text-gray-100">
								<svg
									xmlns="http://www.w3.org/2000/svg"
									viewBox="0 0 20 20"
									fill="currentColor"
									class="w-5 h-5"
								>
									<path
										d="m2.695 14.762-1.262 3.155a.5.5 0 0 0 .65.65l3.155-1.262a4 4 0 0 0 1.343-.886L17.5 5.501a2.121 2.121 0 0 0-3-3L3.58 13.419a4 4 0 0 0-.885 1.343Z"
									/>
								</svg>
							</div>
132
						</div>
133
134
135
136
137
138
139
140
141
142
					</button>
				</div>
				<button
					class=" text-xs text-gray-600"
					on:click={async () => {
						const url = await getGravatarUrl($user.email);

						profileImageUrl = url;
					}}>Use Gravatar</button
				>
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
			</div>

			<div class="flex-1">
				<div class="flex flex-col w-full">
					<div class=" mb-1 text-xs text-gray-500">Name</div>

					<div class="flex-1">
						<input
							class="w-full rounded py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none"
							type="text"
							bind:value={name}
							required
						/>
					</div>
				</div>
			</div>
		</div>

		<hr class=" dark:border-gray-700 my-4" />
		<UpdatePassword />
	</div>

	<div class="flex justify-end pt-3 text-sm font-medium">
		<button
			class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded"
			on:click={async () => {
				const res = await submitHandler();

				if (res) {
					saveHandler();
				}
			}}
		>
			Save
		</button>
	</div>
</div>