Skip to content

Commit

Permalink
Merge pull request #2286 from Plant-for-the-Planet-org/feature/addres…
Browse files Browse the repository at this point in the history
…s-mgmt

BASE: Address Management
  • Loading branch information
mariahosfeld authored Dec 12, 2024
2 parents fcc0fc6 + f2838b1 commit 97fee92
Show file tree
Hide file tree
Showing 26 changed files with 1,819 additions and 199 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"prepare": "node ./husky-prepare.js"
},
"validate-branch-name": {
"pattern": "^(main|develop){1}$|^(feature|hotfix|projects-redesign)/[a-z0-9-_]+$",
"pattern": "^(main|develop){1}$|^(feature|hotfix|address-mgmt)/[a-z0-9-_]+$",
"errorMsg": "Invalid branch name. \n 1.Branch names can contain lowercase characters, numbers, hyphen and underscore. \n 2.Except for 'main' and 'develop', branch names must begin with 'feature/' or 'hotfix/' "
},
"engines": {
Expand Down
23 changes: 13 additions & 10 deletions pages/sites/[slug]/[locale]/profile/edit.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import Head from 'next/head';
import React, { ReactElement } from 'react';
import UserLayout from '../../../../../src/features/common/Layout/UserLayout/UserLayout';
import { AbstractIntlMessages, useTranslations } from 'next-intl';
import EditProfile from '../../../../../src/features/user/Settings/EditProfile';
import {
import type { AbstractIntlMessages } from 'next-intl';
import type {
GetStaticProps,
GetStaticPropsContext,
GetStaticPropsResult,
} from 'next';
import type { Tenant } from '@planet-sdk/common/build/types/tenant';
import type { ReactElement } from 'react';

import { useEffect } from 'react';
import Head from 'next/head';
import { useTranslations } from 'next-intl';
import UserLayout from '../../../../../src/features/common/Layout/UserLayout/UserLayout';
import EditProfile from '../../../../../src/features/user/Settings/EditProfile';
import {
constructPathsForTenantSlug,
getTenantConfig,
} from '../../../../../src/utils/multiTenancy/helpers';
import { Tenant } from '@planet-sdk/common/build/types/tenant';
import { defaultTenant } from '../../../../../tenant.config';
import { useRouter } from 'next/router';
import { useTenant } from '../../../../../src/features/common/Layout/TenantContext';
Expand All @@ -27,7 +30,7 @@ function EditProfilePage({ pageProps: { tenantConfig } }: Props): ReactElement {
const router = useRouter();
const { setTenantConfig } = useTenant();

React.useEffect(() => {
useEffect(() => {
if (router.isReady) {
setTenantConfig(tenantConfig);
}
Expand All @@ -50,7 +53,7 @@ export default EditProfilePage;
export const getStaticPaths = async () => {
const subDomainPaths = await constructPathsForTenantSlug();

const paths = subDomainPaths.map((path) => {
const paths = subDomainPaths?.map((path) => {
return {
params: {
slug: path.params.slug,
Expand Down Expand Up @@ -78,7 +81,7 @@ export const getStaticProps: GetStaticProps<PageProps> = async (

const messages = await getMessagesForPage({
locale: context.params?.locale as string,
filenames: ['common', 'me', 'country', 'editProfile'],
filenames: ['common', 'me', 'country', 'editProfile', 'profile'],
});

return {
Expand Down
11 changes: 11 additions & 0 deletions public/assets/images/icons/KebabMenuIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const KebabMenuIcon = () => {
return (
<svg viewBox="0 0 12 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="4" y="2" width="4" height="4" rx="2" fill="black" />
<rect x="4" y="8" width="4" height="4" rx="2" fill="black" />
<rect x="4" y="14" width="4" height="4" rx="2" fill="black" />
</svg>
);
};

export default KebabMenuIcon;
38 changes: 38 additions & 0 deletions public/static/locales/en/editProfile.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"email": "Email",
"address": "Address",
"city": "City",
"state": "State",
"zipCode": "Postal/Zip Code",
"country": "Country",
"bio": "Your Description",
Expand All @@ -61,11 +62,48 @@
"addressInvalid": "Address is invalid. Only these special characters are allowed: space . , # - /",
"cityRequired": "City is required",
"cityInvalid": "City is invalid. Only letters and these special characters are allowed: space . , ( ) -",
"stateInvalid": "State is invalid. Only letters and these special characters are allowed: space . , ( ) -",
"zipCodeRequired": "Zip Code is required",
"zipCodeInvalid": "Zip Code is invalid",
"websiteInvalid": "Please enter valid Website URL",
"countryRequired": "Country is required",
"companyRequired": "Company Name is required"
},
"addressManagement": {
"labels": {
"actionMenu": "Action menu"
},
"addressManagementTitle": "Address",
"addressType": {
"primary": "Primary Address",
"mailing": "Billing Address"
},
"actions": {
"edit": "Edit",
"delete": "Delete",
"setAsPrimaryAddress": "Set as Primary Address",
"setAsBillingAddress": "Set as Billing Address",
"unsetBillingAddress": "Unset Billing Address",
"addAddress": "Add New Address"
},
"deleteAction": {
"title": "Delete Address",
"deleteButton": "Delete",
"deleteAddressConfirmationMessage": "Are you sure you want to delete this address? If you want to use it again, please add it as a new address."
},
"updateAddressType": {
"setAddressConfirmation": "Are you sure you want to set this address as your {addressType}?",
"replaceAddressWarning": "This will replace your current {addressType}.",
"confirmButton": "Confirm",
"unsetBillingAddressMessage": "Do you want to unset your billing address? Your primary address will be used as billing address."
},
"maxAddressesMessage": "You have reached the maximum number of addresses! Remove one to add a new address.",
"addressForm": {
"addAddress": "Add Address",
"editAddress": "Edit Address",
"saveChanges": "Save Changes",
"address2": "Address 2(optional)"
}
}
}
}
19 changes: 11 additions & 8 deletions src/features/common/InputTypes/AutoCompleteCountry.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
/* eslint-disable no-use-before-define */
import { useState, ReactElement, useEffect, ReactNode } from 'react';
import type { CountryType, ExtendedCountryCode } from '../types/country';
import type { SetState } from '../types/common';
import type { ReactNode, ReactElement } from 'react';
import type { CountryCode } from '@planet-sdk/common';

import { useState, useEffect } from 'react';
import { TextField } from '@mui/material';
import React from 'react';
import { useTranslations } from 'next-intl';
import { MuiAutoComplete, StyledAutoCompleteOption } from './MuiAutoComplete';
import { CountryType, ExtendedCountryCode } from '../types/country';
import { allCountries } from '../../../utils/constants/countries';
import { SetState } from '../types/common';

// ISO 3166-1 alpha-2
// ⚠️ No support for IE 11
Expand Down Expand Up @@ -66,8 +68,8 @@ export default function CountrySelect({

useEffect(() => {
countries.sort((a, b) => {
const nameA = t(a.code.toLowerCase());
const nameB = t(b.code.toLowerCase());
const nameA = t(a.code.toLowerCase() as Lowercase<CountryCode>);
const nameB = t(b.code.toLowerCase() as Lowercase<CountryCode>);

//Automatic Selection option is always at first position (if present)
if (a.code === 'auto') return -1;
Expand All @@ -91,7 +93,8 @@ export default function CountrySelect({
getOptionLabel={(option) => {
const { code: countryCode, currency } = option as CountryType;
const label =
(currency ? `(${currency}) ` : '') + t(countryCode.toLowerCase());
(currency ? `(${currency}) ` : '') +
t(countryCode.toLowerCase() as Lowercase<CountryCode>);
return label;
}}
isOptionEqualToValue={(option, value) =>
Expand All @@ -101,7 +104,7 @@ export default function CountrySelect({
const { code: countryCode, currency } = option as CountryType;
const displayedOption =
(currency ? `(${currency}) ` : '') +
t(countryCode.toLowerCase()) +
t(countryCode.toLowerCase() as Lowercase<CountryCode>) +
(!(name == 'editProfile' || countryCode === 'auto')
? ` ${countryCode}`
: '');
Expand Down
12 changes: 9 additions & 3 deletions src/features/common/types/profile.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { User, UserPublicProfile } from '@planet-sdk/common';
import { SetState } from './common';
import { PublicUser } from './user';
import type { User, UserPublicProfile } from '@planet-sdk/common';
import type { SetState } from './common';
import type { PublicUser } from './user';
import type { ADDRESS_ACTIONS } from '../../../utils/addressManagement';

export interface UserFeaturesProps {
handleShare: () => void;
Expand All @@ -25,3 +26,8 @@ export type PublicProfileV2Props = {
};

export type ProfileV2Props = PrivateProfileV2Props | PublicProfileV2Props;

// address management

export type AddressAction =
(typeof ADDRESS_ACTIONS)[keyof typeof ADDRESS_ACTIONS];
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,10 @@
position: relative;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 398px;
height: 524px;
background: #fff;
transform: translate(-50%, -50%);
border-radius: 16px;
padding: 18px;
display: flex;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import type { ExtendedCountryCode } from '../../../../common/types/country';
import type { SetState } from '../../../../common/types/common';
import type { Address, APIError } from '@planet-sdk/common';
import type { AddressAction } from '../../../../common/types/profile';

import { useState, useContext, useCallback } from 'react';
import { useTranslations } from 'next-intl';
import { handleError } from '@planet-sdk/common';
import { useUserProps } from '../../../../common/Layout/UserPropsContext';
import { postAuthenticatedRequest } from '../../../../../utils/apiRequests/api';
import { useTenant } from '../../../../common/Layout/TenantContext';
import { ErrorHandlingContext } from '../../../../common/Layout/ErrorHandlingContext';
import AddressForm from './microComponents/AddressForm';
import { ADDRESS_TYPE } from '../../../../../utils/addressManagement';
import AddressFormLayout from './microComponents/AddressFormLayout';
import { getStoredConfig } from '../../../../../utils/storeConfig';

export type FormData = {
address: string | undefined;
address2: string | null;
city: string | undefined;
zipCode: string | undefined;
state: string | null;
};

interface Props {
setIsModalOpen: SetState<boolean>;
setUserAddresses: SetState<Address[]>;
setAddressAction: SetState<AddressAction | null>;
}

const defaultAddressDetail = {
address: '',
address2: '',
city: '',
zipCode: '',
state: '',
};

const AddAddress = ({
setIsModalOpen,
setUserAddresses,
setAddressAction,
}: Props) => {
const tAddressManagement = useTranslations('EditProfile.addressManagement');
const { contextLoaded, user, token, logoutUser } = useUserProps();
const configCountry = getStoredConfig('country');
const defaultCountry = user?.country || configCountry || 'DE';
const { tenantConfig } = useTenant();
const { setErrors } = useContext(ErrorHandlingContext);
const [country, setCountry] = useState<ExtendedCountryCode | ''>(
defaultCountry
);
const [isLoading, setIsLoading] = useState(false);

const addAddress = useCallback(
async (data: FormData) => {
if (!contextLoaded || !user || !token) return;
setIsLoading(true);
const bodyToSend = {
...data,
country,
type: ADDRESS_TYPE.OTHER,
};
try {
const res = await postAuthenticatedRequest<Address>(
tenantConfig.id,
'/app/addresses',
bodyToSend,
token,
logoutUser
);
if (res && setUserAddresses) {
setUserAddresses((prevAddresses) => [...prevAddresses, res]);
}
} catch (error) {
setErrors(handleError(error as APIError));
} finally {
setIsLoading(false);
setIsModalOpen(false);
setAddressAction(null);
}
},
[
contextLoaded,
user,
token,
country,
logoutUser,
setUserAddresses,
handleError,
setIsLoading,
setIsModalOpen,
postAuthenticatedRequest,
]
);

return (
<AddressFormLayout label={tAddressManagement('addressForm.addAddress')}>
<AddressForm
country={country}
setCountry={setCountry}
setIsModalOpen={setIsModalOpen}
isLoading={isLoading}
label={tAddressManagement('addressForm.addAddress')}
defaultAddressDetail={defaultAddressDetail}
processFormData={addAddress}
setAddressAction={setAddressAction}
/>
</AddressFormLayout>
);
};

export default AddAddress;
Loading

0 comments on commit 97fee92

Please sign in to comment.