Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,13 @@ const baseProfile: ApiIdentity = {
function renderComponent(profile: Partial<ApiIdentity>, mainAddress = '0xabc') {
const combined = { ...baseProfile, ...profile } as ApiIdentity;
return render(
<UserPageHeaderName profile={combined} canEdit={false} mainAddress={mainAddress} />
<UserPageHeaderName
profile={combined}
canEdit={false}
mainAddress={mainAddress}
level={combined.level}
profileEnabledAt={null}
/>
);
}

Expand Down
2 changes: 1 addition & 1 deletion components/user/layout/UserPageLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function UserPageLayout({
handleOrWallet={normalizedHandleOrWallet}
fallbackMainAddress={mainAddress}
/>
<div className="tw-px-2 lg:tw-px-6 xl:tw-px-8 tw-mx-auto">
<div className="tw-px-4 sm:tw-px-6 md:tw-px-8 tw-mx-auto">
<UserPageTabs />
<div className="tw-mt-6 lg:tw-mt-8">{children}</div>
</div>
Expand Down
156 changes: 156 additions & 0 deletions components/user/settings/UserSettingsBannerImageInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
"use client";

import { useContext, useEffect, useState } from "react";
import { AuthContext } from "@/components/auth/Auth";

const ACCEPTED_FORMATS = [
"image/jpeg",
"image/jpg",
"image/png",
"image/gif",
"image/webp",
];

const ACCEPTED_FORMATS_DISPLAY = ACCEPTED_FORMATS.map(
(format) => `.${format.replace("image/", "")}`
).join(", ");

const FILE_SIZE_LIMIT = 10485760;

export default function UserSettingsBannerImageInput({
imageToShow,
setFile,
}: {
readonly imageToShow: string | null;
readonly setFile: (file: File) => void;
}) {
const { setToast } = useContext(AuthContext);
const [error, setError] = useState<string | null>(null);
const [shake, setShake] = useState<boolean>(false);
const [dragging, setDragging] = useState(false);

const onFileChange = (file: File) => {
setError(null);
if (ACCEPTED_FORMATS.indexOf(file.type) === -1) {
setToast({
type: "error",
message: "Invalid file type",
});
return;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

if (file.size > FILE_SIZE_LIMIT) {
setError("File size must be less than 10MB");
setShake(true);
return;
}

setError(null);
setFile(file);
};

const handleDrop = (e: any) => {
e.preventDefault();
e.stopPropagation();
if (e?.dataTransfer?.files?.length) {
onFileChange(e.dataTransfer.files[0]);
}
};

const handleDrag = (e: any) => {
e.preventDefault();
e.stopPropagation();
if (e.type === "dragenter" || e.type === "dragover") {
setDragging(true);
} else if (e.type === "dragleave") {
setDragging(false);
} else if (e.type === "drop") {
setDragging(false);
}
Comment thread
ragnep marked this conversation as resolved.
Outdated
};

useEffect(() => {
if (shake) {
const timeout = setTimeout(() => setShake(false), 300);
return () => clearTimeout(timeout);
}
return;
}, [shake]);

return (
<div
onDrop={handleDrop}
onDragEnter={handleDrag}
onDragLeave={handleDrag}
onDragOver={handleDrag}
className="tw-group tw-flex tw-w-full tw-items-center tw-justify-center"
>
<label
className={` ${
dragging
? "tw-border-iron-600 tw-bg-iron-800"
: "tw-border-iron-700 tw-bg-iron-900"
} tw-relative tw-flex tw-h-48 tw-w-full tw-cursor-pointer tw-flex-col tw-items-center tw-justify-center tw-rounded-lg tw-border-2 tw-border-dashed tw-transition tw-duration-300 tw-ease-out hover:tw-border-iron-600 hover:tw-bg-iron-800 ${
shake ? "tw-animate-shake" : ""
} `}
>
<div className="tw-flex tw-flex-col tw-items-center tw-justify-center tw-gap-3 tw-px-4">
{imageToShow ? (
<div className="tw-h-24 tw-w-full tw-overflow-hidden tw-rounded-md tw-ring-1 tw-ring-iron-800">
<img
src={imageToShow}
alt="Banner preview"
className="tw-h-full tw-w-full tw-object-cover"
/>
</div>
) : (
<div className="tw-flex tw-h-10 tw-w-10 tw-items-center tw-justify-center tw-rounded-lg tw-border tw-border-solid tw-border-iron-700 tw-bg-iron-900 tw-transition tw-duration-300 tw-ease-out group-hover:tw-bg-iron-800">
<div className="tw-flex tw-h-5 tw-w-5 tw-flex-shrink-0 tw-items-center tw-justify-center tw-text-iron-50">
<svg
className="tw-h-6 tw-w-6 tw-flex-shrink-0 tw-text-iron-50"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4 16.2422C2.79401 15.435 2 14.0602 2 12.5C2 10.1564 3.79151 8.23129 6.07974 8.01937C6.54781 5.17213 9.02024 3 12 3C14.9798 3 17.4522 5.17213 17.9203 8.01937C20.2085 8.23129 22 10.1564 22 12.5C22 14.0602 21.206 15.435 20 16.2422M8 16L12 12M12 12L16 16M12 12V21"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</div>
</div>
)}
<div className="tw-flex tw-flex-col tw-items-center tw-justify-center">
<p className="tw-mb-1 tw-text-sm tw-font-normal tw-text-iron-400">
<span className="tw-font-medium tw-text-white">
Click to upload
</span>{" "}
or drag and drop
</p>
<p className="tw-text-xs tw-font-normal tw-text-iron-400">
JPEG, JPG, PNG, GIF, WEBP — max 10MB
</p>
</div>
{error && (
<p className="tw-text-xs tw-font-medium tw-text-red">{error}</p>
)}
</div>
<input
id="banner-upload-input"
type="file"
className="tw-hidden"
accept={ACCEPTED_FORMATS_DISPLAY}
onChange={(e: any) => {
if (e.target.files) {
const f = e.target.files[0];
onFileChange(f);
}
}}
/>
</label>
</div>
);
}
Loading