Skip to content

Commit

Permalink
add image size checks to profile manage
Browse files Browse the repository at this point in the history
  • Loading branch information
NickJ202 committed Aug 2, 2024
1 parent 49878d7 commit f1a61e8
Show file tree
Hide file tree
Showing 11 changed files with 77 additions and 31 deletions.
4 changes: 2 additions & 2 deletions src/components/atoms/Avatar/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ReactSVG } from 'react-svg';

import { ASSETS } from 'helpers/config';
import { getTxEndpoint } from 'helpers/endpoints';
import { checkAddress } from 'helpers/utils';
import { checkValidAddress } from 'helpers/utils';

import * as S from './styles';
import { IProps } from './types';
Expand All @@ -12,7 +12,7 @@ export default function Avatar(props: IProps) {
const [hasError, setHasError] = React.useState(false);

const avatar = React.useMemo(() => {
if (!hasError && props.owner && props.owner.avatar && checkAddress(props.owner.avatar)) {
if (!hasError && props.owner && props.owner.avatar && checkValidAddress(props.owner.avatar)) {
return <img src={getTxEndpoint(props.owner.avatar)} onError={() => setHasError(true)} />;
} else return <ReactSVG src={ASSETS.user} />;
}, [props.owner, hasError]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ReactSVG } from 'react-svg';
import { Button } from 'components/atoms/Button';
import { TxAddress } from 'components/atoms/TxAddress';
import { ASSETS, REDIRECTS } from 'helpers/config';
import { checkAddress, getDisplayValue, splitLicenseTag } from 'helpers/utils';
import { checkValidAddress, getDisplayValue, splitLicenseTag } from 'helpers/utils';
import { useLanguageProvider } from 'providers/LanguageProvider';

import * as S from './styles';
Expand Down Expand Up @@ -44,7 +44,7 @@ export default function AssetDetailLicenses(props: IProps) {
</S.LFlex>
);
} else {
if (checkAddress(props.asset.license[element])) {
if (checkValidAddress(props.asset.license[element])) {
return (
<TxAddress
address={props.asset.license[element]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Modal } from 'components/molecules/Modal';
import { Table } from 'components/molecules/Table';
import { AO, ASSETS, PAGINATORS, REDIRECTS, URLS } from 'helpers/config';
import { AlignType, CollectionType } from 'helpers/types';
import { checkAddress, formatAddress } from 'helpers/utils';
import { checkValidAddress, formatAddress } from 'helpers/utils';
import { useArweaveProvider } from 'providers/ArweaveProvider';
import { useLanguageProvider } from 'providers/LanguageProvider';
import { RootState } from 'store';
Expand Down Expand Up @@ -43,7 +43,7 @@ function CollectionDropdown(props: { id: string; title: string }) {

React.useEffect(() => {
(async function () {
if (props.id && checkAddress(props.id) && listingModalOpen && !collection) {
if (props.id && checkValidAddress(props.id) && listingModalOpen && !collection) {
setFetchingCollection(true);
try {
const fetchResponse = await readHandler({
Expand Down
37 changes: 28 additions & 9 deletions src/components/organisms/ProfileManage/ProfileManage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { TextArea } from 'components/atoms/TextArea';
import { AO, ASSETS, GATEWAYS, TAGS } from 'helpers/config';
import { getTxEndpoint } from 'helpers/endpoints';
import { NotificationType } from 'helpers/types';
import { checkAddress, getBase64Data, getDataURLContentType } from 'helpers/utils';
import { checkValidAddress, getBase64Data, getDataURLContentType } from 'helpers/utils';
import { useArweaveProvider } from 'providers/ArweaveProvider';
import { useLanguageProvider } from 'providers/LanguageProvider';
import { WalletBlock } from 'wallet/WalletBlock';
Expand All @@ -22,6 +22,7 @@ import * as S from './styles';
import { IProps } from './types';

const MAX_BIO_LENGTH = 500;
const MAX_IMAGE_SIZE = 100000;
const ALLOWED_BANNER_TYPES = 'image/png, image/jpeg, image/gif';
const ALLOWED_AVATAR_TYPES = 'image/png, image/jpeg, image/gif';

Expand All @@ -48,8 +49,8 @@ export default function ProfileManage(props: IProps) {
setUsername(props.profile.username ?? '');
setName(props.profile.displayName ?? '');
setBio(props.profile.bio ?? '');
setBanner(props.profile.banner && checkAddress(props.profile.banner) ? props.profile.banner : null);
setAvatar(props.profile.avatar && checkAddress(props.profile.avatar) ? props.profile.avatar : null);
setBanner(props.profile.banner && checkValidAddress(props.profile.banner) ? props.profile.banner : null);
setAvatar(props.profile.avatar && checkValidAddress(props.profile.avatar) ? props.profile.avatar : null);
}
}, [props.profile]);

Expand All @@ -70,7 +71,7 @@ export default function ProfileManage(props: IProps) {

let bannerTx: any = null;
if (banner) {
if (checkAddress(banner)) {
if (checkValidAddress(banner)) {
bannerTx = banner;
} else {
try {
Expand All @@ -91,7 +92,7 @@ export default function ProfileManage(props: IProps) {

let avatarTx: any = null;
if (avatar) {
if (checkAddress(avatar)) {
if (checkValidAddress(avatar)) {
avatarTx = avatar;
} else {
try {
Expand Down Expand Up @@ -251,6 +252,20 @@ export default function ProfileManage(props: IProps) {
}
}

function getImageSizeMessage() {
if (!avatar && !banner) return null;
if (checkValidAddress(avatar) && checkValidAddress(banner)) return null;

const avatarSize = avatar ? (avatar.length * 3) / 4 : 0;
const bannerSize = banner ? (banner.length * 3) / 4 : 0;

console.log(avatarSize);

if (avatarSize > MAX_IMAGE_SIZE || bannerSize > MAX_IMAGE_SIZE)
return <span>One or more images exceeds max size of 100KB</span>;
return null;
}

function getInvalidBio() {
if (bio && bio.length > MAX_BIO_LENGTH) {
return {
Expand Down Expand Up @@ -289,7 +304,7 @@ export default function ProfileManage(props: IProps) {
}

function getBannerWrapper() {
if (banner) return <img src={checkAddress(banner) ? getTxEndpoint(banner) : banner} />;
if (banner) return <img src={checkValidAddress(banner) ? getTxEndpoint(banner) : banner} />;
return (
<>
<ReactSVG src={ASSETS.media} />
Expand All @@ -299,7 +314,7 @@ export default function ProfileManage(props: IProps) {
}

function getAvatarWrapper() {
if (avatar) return <img src={checkAddress(avatar) ? getTxEndpoint(avatar) : avatar} />;
if (avatar) return <img src={checkValidAddress(avatar) ? getTxEndpoint(avatar) : avatar} />;
return (
<>
<ReactSVG src={ASSETS.user} />
Expand Down Expand Up @@ -360,9 +375,12 @@ export default function ProfileManage(props: IProps) {
disabled={loading || !banner}
/>
</S.PActions>
<S.PInfoMessage>
<span>Images have a max size of 100KB</span>
</S.PInfoMessage>
</S.PWrapper>
<S.Form>
<S.TForm className={'border-wrapper-alt2'}>
<S.TForm>
<FormField
label={language.name}
value={name}
Expand Down Expand Up @@ -409,10 +427,11 @@ export default function ProfileManage(props: IProps) {
type={'alt1'}
label={language.save}
handlePress={handleSubmit}
disabled={!username || !name || loading}
disabled={!username || !name || loading || getImageSizeMessage() !== null}
loading={loading}
/>
</S.SAction>
{getImageSizeMessage() && <S.MInfoWrapper>{getImageSizeMessage()}</S.MInfoWrapper>}
</S.Body>
</S.Wrapper>
{profileResponse && (
Expand Down
29 changes: 28 additions & 1 deletion src/components/organisms/ProfileManage/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ export const Form = styled.div`

export const TForm = styled.div`
margin: 20px 0 30px 0;
padding: 20px;
> * {
&:last-child {
margin: 20px 0 0 0;
Expand Down Expand Up @@ -261,6 +260,18 @@ export const PActions = styled.div`
}
`;

export const PInfoMessage = styled.div`
margin: 15px 0 0 0;
display: flex;
justify-content: flex-end;
span {
color: ${(props) => props.theme.colors.font.alt1};
font-size: ${(props) => props.theme.typography.size.xSmall};
font-weight: ${(props) => props.theme.typography.weight.medium};
line-height: 1.5;
}
`;

export const SAction = styled.div`
width: 100%;
display: flex;
Expand Down Expand Up @@ -304,3 +315,19 @@ export const MActions = styled.div`
flex-wrap: wrap;
gap: 15px;
`;

export const MInfoWrapper = styled.div`
width: fit-content;
margin: 10px 0 0 auto;
span {
background: ${(props) => props.theme.colors.warning};
color: ${(props) => props.theme.colors.font.light1};
font-size: ${(props) => props.theme.typography.size.xxSmall};
font-weight: ${(props) => props.theme.typography.weight.bold};
border-radius: ${STYLING.dimensions.radius.alt2};
text-align: center;
display: block;
padding: 2.5px 12.5px;
margin: 0 0 7.5px 0;
}
`;
4 changes: 2 additions & 2 deletions src/gql/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { getGQLData, getProfiles, structureAsset } from 'gql';

import { GATEWAYS, TAGS } from 'helpers/config';
import { AGQLResponseType, AssetGQLResponseType, AssetType, CursorEnum, GQLNodeResponseType } from 'helpers/types';
import { checkAddress, getTagValue } from 'helpers/utils';
import { checkValidAddress, getTagValue } from 'helpers/utils';

export async function search(args: { term: string; cursor: string | null }): Promise<AssetGQLResponseType | null> {
const emptyResponseObject = {
Expand All @@ -12,7 +12,7 @@ export async function search(args: { term: string; cursor: string | null }): Pro
previousCursor: null,
};
try {
const addressCheck = checkAddress(args.term);
const addressCheck = checkValidAddress(args.term);

const gqlResponse: AGQLResponseType = await getGQLData({
gateway: GATEWAYS.goldsky,
Expand Down
4 changes: 2 additions & 2 deletions src/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Arweave from 'arweave';
import { API_CONFIG, GATEWAYS, STORAGE } from './config';
import { DateType, ProfileType } from './types';

export function checkAddress(address: string | null) {
export function checkValidAddress(address: string | null) {
if (!address) return false;
return /^[a-z0-9_-]{43}$/i.test(address);
}
Expand All @@ -14,7 +14,7 @@ export function getUniqueAddresses(addresses: string[]) {

export function formatAddress(address: string | null, wrap: boolean) {
if (!address) return '';
if (!checkAddress(address)) return address;
if (!checkValidAddress(address)) return address;
const formattedAddress = address.substring(0, 5) + '...' + address.substring(36, address.length);
return wrap ? `(${formattedAddress})` : formattedAddress;
}
Expand Down
6 changes: 3 additions & 3 deletions src/views/Landing/Profile/Profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { ProfileManage } from 'components/organisms/ProfileManage';
import { ASSETS, REDIRECTS, URLS } from 'helpers/config';
import { getTxEndpoint } from 'helpers/endpoints';
import { ProfileHeaderType } from 'helpers/types';
import { checkAddress, formatAddress } from 'helpers/utils';
import { checkValidAddress, formatAddress } from 'helpers/utils';
import { useArweaveProvider } from 'providers/ArweaveProvider';
import { useLanguageProvider } from 'providers/LanguageProvider';

Expand Down Expand Up @@ -48,7 +48,7 @@ export default function Profile(props: { address: string }) {

React.useEffect(() => {
(async function () {
if (props.address && checkAddress(props.address)) {
if (props.address && checkValidAddress(props.address)) {
setLoading(true);
try {
const currentProfile = await getProfile({ address: props.address });
Expand All @@ -62,7 +62,7 @@ export default function Profile(props: { address: string }) {
}, [props.address, arProvider.profile]);

function getAvatar() {
if (fullProfile && fullProfile.avatar && checkAddress(fullProfile.avatar))
if (fullProfile && fullProfile.avatar && checkValidAddress(fullProfile.avatar))
return <img src={getTxEndpoint(fullProfile.avatar)} />;
return <ReactSVG src={ASSETS.user} />;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { FormField } from 'components/atoms/FormField';
import { Select } from 'components/atoms/Select';
import { ASSETS } from 'helpers/config';
import { SelectOptionType } from 'helpers/types';
import { checkAddress, concatLicenseTag } from 'helpers/utils';
import { checkValidAddress, concatLicenseTag } from 'helpers/utils';
import { useArweaveProvider } from 'providers/ArweaveProvider';
import { useLanguageProvider } from 'providers/LanguageProvider';
import { RootState } from 'store';
Expand Down Expand Up @@ -247,7 +247,7 @@ export default function UploadStepsLicenseFull(props: IProps) {
dataModelTrainingTermAmount <= 0) ||
(paymentMode &&
paymentMode.id === concatLicenseTag(licenseParams.paymentMode.single) &&
!checkAddress(paymentRecipient))
!checkValidAddress(paymentRecipient))
) {
dispatch(uploadActions.setStepDisabled(true));
} else {
Expand Down Expand Up @@ -393,7 +393,7 @@ export default function UploadStepsLicenseFull(props: IProps) {
label={language.recipient}
value={paymentRecipient}
onChange={(e: any) => setPaymentRecipient(e.target.value)}
invalid={{ status: paymentRecipient ? !checkAddress(paymentRecipient) : true, message: null }}
invalid={{ status: paymentRecipient ? !checkValidAddress(paymentRecipient) : true, message: null }}
disabled={disabled}
hideErrorMessage
required
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/WalletConnect/WalletConnect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export default function WalletConnect(_props: { callback?: () => void }) {
<Avatar owner={arProvider.profile} dimensions={{ wrapper: 32.5, icon: 21.5 }} callback={handlePress} />
</S.PWrapper>
{showWalletDropdown && (
<S.Dropdown className={'border-wrapper-primary'}>
<S.Dropdown className={'border-wrapper-alt2'}>
<S.DHeaderWrapper>
<S.DHeaderFlex>
<Avatar owner={arProvider.profile} dimensions={{ wrapper: 35, icon: 23.5 }} callback={null} />
Expand Down
8 changes: 4 additions & 4 deletions src/wallet/WalletConnect/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const FlexAction = styled.div`
`;

export const Dropdown = styled.ul`
width: 350px;
width: 315px;
max-width: 90vw;
padding: 20px 0 10px 0;
position: absolute;
Expand Down Expand Up @@ -88,8 +88,8 @@ export const DHeader = styled.div`
export const BWrapper = styled.div`
margin: 20px 0 0 0;
padding: 15px;
border-top: 1px solid ${(props) => props.theme.colors.border.primary};
border-bottom: 1px solid ${(props) => props.theme.colors.border.primary};
border-top: 1px solid ${(props) => props.theme.colors.border.alt4};
border-bottom: 1px solid ${(props) => props.theme.colors.border.alt4};
p {
color: ${(props) => props.theme.colors.font.primary};
font-size: ${(props) => props.theme.typography.size.small};
Expand Down Expand Up @@ -156,6 +156,6 @@ export const DBodyWrapper = styled.ul`

export const DFooterWrapper = styled(DBodyWrapper)`
padding: 10px 0 0 0;
border-top: 1px solid ${(props) => props.theme.colors.border.primary};
border-top: 1px solid ${(props) => props.theme.colors.border.alt4};
border-bottom: none;
`;

0 comments on commit f1a61e8

Please sign in to comment.