Skip to content

Commit

Permalink
Merge pull request #202 from alexookah/create_use_country
Browse files Browse the repository at this point in the history
Create use country composable
  • Loading branch information
scottyzen authored Aug 19, 2024
2 parents c4deb6b + 1dacd86 commit a0b0441
Show file tree
Hide file tree
Showing 8 changed files with 359 additions and 268 deletions.
13 changes: 8 additions & 5 deletions woonuxt_base/app/components/forms/BillingDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ const props = defineProps({
});
const billing = toRef(props, 'modelValue');
const { allowedCountries, countryStates } = await GqlGetStates({ country: billing.value.country });
</script>

<template>
Expand Down Expand Up @@ -41,12 +38,18 @@ const { allowedCountries, countryStates } = await GqlGetStates({ country: billin

<div v-if="isBillingAddressEnabled" class="w-full">
<label for="state">{{ $t('messages.billing.state') }} ({{ $t('messages.general.optional') }})</label>
<StateSelect id="state" v-model="billing.state" :default-value="billing.state" :country-code="billing.country" @change="updateShippingLocation" :countryStates />
<StateSelect
id="state"
v-model="billing.state"
:default-value="billing.state"
:country-code="billing.country"
@change="updateShippingLocation"
autocomplete="address-level1" />
</div>

<div v-if="isBillingAddressEnabled" class="w-full">
<label for="country">{{ $t('messages.billing.country') }}</label>
<CountrySelect id="country" v-model="billing.country" :default-value="billing.country" @change="updateShippingLocation" :allowedCountries />
<CountrySelect id="country" v-model="billing.country" :default-value="billing.country" @change="updateShippingLocation" autocomplete="country" />
</div>

<div v-if="isBillingAddressEnabled" class="w-full">
Expand Down
18 changes: 11 additions & 7 deletions woonuxt_base/app/components/shopElements/CountrySelect.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
<script setup>
import { countries } from '#constants';
const props = defineProps(['modelValue', 'props.allowedCountries']);
const props = defineProps({
modelValue: { type: String, default: '' },
});
const { getAllowedCountries, countriesToShow } = useCountry();
const emit = defineEmits(['update:modelValue']);
const countriesToShow = computed(() =>
props.allowedCountries?.length ? countries.filter((country) => props.allowedCountries.includes(country.countryCode)) : countries,
);
onMounted(() => {
getAllowedCountries();
});
function select(evt) {
emit('update:modelValue', evt.target.value);
Expand All @@ -15,8 +19,8 @@ function select(evt) {
<template>
<select :value="modelValue" @change="select" required>
<option value="" disabled>Select a country</option>
<option v-for="country in countriesToShow" :key="country.countryName" :value="country.countryCode">
{{ country.countryName }}
<option v-for="country in countriesToShow" :key="country.code" :value="country.code">
{{ country.name }}
</option>
</select>
</template>
Expand Down
25 changes: 16 additions & 9 deletions woonuxt_base/app/components/shopElements/StateSelect.vue
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
<script setup>
const props = defineProps(['modelValue', 'countryCode', 'countryStates']);
const props = defineProps({
modelValue: { type: String, default: '' },
countryCode: { type: String, default: '' },
});
const { getStatesForCountry, countryStatesDict } = useCountry();
const emit = defineEmits(['update:modelValue']);
const states = ref(props.countryStates || []);
function select(evt) {
emit('update:modelValue', evt.target.value);
}
async function updateState() {
try {
const { countryStates } = await GqlGetStates({ country: props?.countryCode || 'IE' });
states.value = countryStates;
} catch (error) {
console.error(error);
if (props.countryCode && props.countryCode.length > 0) {
await getStatesForCountry(props.countryCode);
}
}
onMounted(() => {
updateState();
});
watch(
() => props.countryCode,
() => {
Expand All @@ -25,8 +31,9 @@ watch(
</script>

<template>
<select @change="select" v-if="states.length" class="h-[42px]">
<option v-for="state in states" :key="state.code" :value="state.code" :selected="state.code === props.modelValue">
<select @change="select" v-if="countryStatesDict[props.countryCode]?.length" class="h-[42px]">
<option value="" :selected="!props.modelValue">Select a state</option>
<option v-for="state in countryStatesDict[props.countryCode]" :key="state.code" :value="state.code" :selected="state.code === props.modelValue">
{{ state.name }}
</option>
</select>
Expand Down
70 changes: 70 additions & 0 deletions woonuxt_base/app/composables/useCountry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import type { CountriesEnum } from '#gql/default';
import { countries } from '#constants';

export const useCountry = () => {
// State to store allowed countries
const allowedCountries = useState<CountriesEnum[] | null>('allowedCountries', () => null);
const isLoadingAllowedCountries = useState<boolean>('isLoadingAllowedCountries', () => false);

// State to store the countries to be shown - init with static countries
const countriesToShow = useState<GeoLocation[]>('countriesToShow', () => countries);

// State to store states for each country state
const countryStatesDict = useState<{ [code: string]: GeoLocation[] }>('countryStatesDict', () => ({}));
const isLoadingCountryStates = useState<{ [code: string]: boolean }>('isLoadingCountryStates', () => ({}));

// Function to get allowed countries from API
async function getAllowedCountries() {
if (allowedCountries.value || isLoadingAllowedCountries.value) {
return;
}

isLoadingAllowedCountries.value = true;

try {
const response = await GqlGetAllowedCountries();
if (response.allowedCountries) {
// Filter out null values and store the result
allowedCountries.value = response.allowedCountries.filter(
(country): country is CountriesEnum => country !== null
);

// Filter countries to show based on allowed countries
countriesToShow.value = countries.filter(
(country) => allowedCountries.value?.includes(country.code as CountriesEnum)
);
}
} catch (error) {
console.error('Failed to retrieve allowed countries', error);
} finally {
isLoadingAllowedCountries.value = false;
}
}

// Function to get states for a specific country from API - once
async function getStatesForCountry(countryCode: CountriesEnum) {
if (countryStatesDict.value[countryCode] || isLoadingCountryStates.value[countryCode]) {
return;
}

isLoadingCountryStates.value[countryCode] = true;

try {
const { countryStates } = await GqlGetStates({ country: countryCode });
if (countryStates) {
countryStatesDict.value[countryCode] = countryStates as GeoLocation[];
}
} catch (error) {
console.error(`Failed to retrieve states for country ${countryCode}`, error);
} finally {
isLoadingCountryStates.value[countryCode] = false;
}
}

return {
getAllowedCountries,
countriesToShow,
getStatesForCountry,
countryStatesDict,
};
};
Loading

0 comments on commit a0b0441

Please sign in to comment.