Skip to content

Commit

Permalink
refactor: Improved the UX of the "choose my location" feature
Browse files Browse the repository at this point in the history
  • Loading branch information
FleetAdmiralJakob committed Jan 3, 2024
1 parent e838253 commit 55e9d81
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 43 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ UPSTASH_RATELIMITER_TOKENS_PER_TIME="..."
UPSTASH_RATELIMITER_TIME_INTERVAL="..."
RESEND_API_KEY="re_..."
QWEATHER_API_KEY="..."
API_NINJA_API_KEY="..."
2 changes: 1 addition & 1 deletion public/locales/de/locationsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"city not found toast": "Stadt nicht gefunden!",
"try again toast": "Versuche es erneut!",

"my city button": "Meine Stadt auswählen"
"my location button": "Meinen Standort auswählen"
}
2 changes: 1 addition & 1 deletion public/locales/de/search.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"search input placeholder": "Suche deinen Standort",
"continue button": "Weiter -->",

"my city button": "Meine Stadt auswählen"
"my location button": "Meinen Standort auswählen"
}
2 changes: 1 addition & 1 deletion public/locales/en/locationsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"city not found toast": "City not found!",
"try again toast": "Try again!",

"my city button": "Choose my city"
"my location button": "Choose my location"
}
2 changes: 1 addition & 1 deletion public/locales/en/search.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"search input placeholder": "Search for your location",
"continue button": "Continue -->",

"my city button": "Choose my city"
"my location button": "Choose my location"
}
8 changes: 5 additions & 3 deletions src/env.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { z } from 'zod'
import {z} from 'zod'

/**
* Specify your server-side environment variables schema here. This way you can ensure the app isn't
Expand All @@ -12,7 +12,8 @@ const server = z.object({
UPSTASH_RATELIMITER_TOKENS_PER_TIME: z.string().min(1),
UPSTASH_RATELIMITER_TIME_INTERVAL: z.string().min(1),
RESEND_API_KEY: z.string().min(1),
QWEATHER_API_KEY: z.string().min(1)
QWEATHER_API_KEY: z.string().min(1),
API_NINJA_API_KEY: z.string().min(1),
})

/**
Expand All @@ -39,7 +40,8 @@ const processEnv = {
UPSTASH_RATELIMITER_TIME_INTERVAL:
process.env.UPSTASH_RATELIMITER_TIME_INTERVAL,
RESEND_API_KEY: process.env.RESEND_API_KEY,
QWEATHER_API_KEY: process.env.QWEATHER_API_KEY
QWEATHER_API_KEY: process.env.QWEATHER_API_KEY,
API_NINJA_API_KEY: process.env.API_NINJA_API_KEY,
// NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR,
}

Expand Down
38 changes: 22 additions & 16 deletions src/pages/locationsettings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@ const LocationSettings = observer(() => {
name: searchValue.name,
});

const findCityByCoordinatesMutation =
api.reverseGeoRouter.getCity.useMutation({
onSuccess: (data) => {
if (data) {
setSearchValue(data);
} else {
toast.error(translationLocationSettings("city not found toast"));
}
},
});

useEffect(() => {
if (searchValue.name === "") {
setResults([]);
Expand Down Expand Up @@ -77,12 +88,15 @@ const LocationSettings = observer(() => {
lat: 0,
},
};
if (searchValue.id === -1) {
if (
searchValue.id.toString().length === 15 ||
searchValue.id.toString().length === 14
) {
city = {
id: -1,
id: searchValue.id,
name: searchValue.name,
country: "",
region: "",
country: searchValue.country,
region: searchValue.region,
coord: {
lon: searchValue.coord.lon,
lat: searchValue.coord.lat,
Expand Down Expand Up @@ -309,23 +323,15 @@ const LocationSettings = observer(() => {
navigator.geolocation.getCurrentPosition((position) => {
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
const city: ICity = {
id: -1,
name: translationCommon("my city"),
country: "",
region: "",
coord: {
lon: longitude,
lat: latitude,
},
};

setSearchValue(city);
findCityByCoordinatesMutation.mutate({
coordinates: { lat: latitude, lng: longitude },
});
});
}
}}
>
{translationLocationSettings("my city button")}
{translationLocationSettings("my location button")}
</button>
<button
onClick={() => {
Expand Down
42 changes: 22 additions & 20 deletions src/pages/search/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ const Search = () => {
name: searchValue.name,
});

const findCityByCoordinatesMutation =
api.reverseGeoRouter.getCity.useMutation({
onSuccess: (data) => {
if (data) {
setSearchValue(data);
} else {
toast.error(translationLocationSettings("city not found toast"));
}
},
});

useEffect(() => {
if (searchValue.name === "") {
setResults([]);
Expand All @@ -72,20 +83,22 @@ const Search = () => {
lat: 0,
},
};
if (searchValue.id === -1) {
if (
searchValue.id.toString().length === 15 ||
searchValue.id.toString().length === 14
) {
city = {
id: -1,
id: searchValue.id,
name: searchValue.name,
country: "",
region: "",
country: searchValue.country,
region: searchValue.region,
coord: {
lon: searchValue.coord.lon,
lat: searchValue.coord.lat,
},
};
} else {
if (searchValue.id !== 0 && searchValue.country !== "") {
console.log("hi");
if (findCityByIdStatus === "loading") {
toast.loading(translationLocationSettings("try again toast"));
return;
Expand All @@ -97,14 +110,11 @@ const Search = () => {
return;
}
} else {
console.log("hi");
if (findCityByNameStatus === "loading") {
toast.loading(translationLocationSettings("try again toast"));
return;
}
console.log("hi 2");
if (!Array.isArray(findCityByNameData)) {
console.log("hi 3");
city = findCityByNameData.city;
} else {
toast.error(translationLocationSettings("city not found toast"));
Expand Down Expand Up @@ -265,23 +275,15 @@ const Search = () => {
navigator.geolocation.getCurrentPosition((position) => {
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
const city: ICity = {
id: -1,
name: translationCommon("my city"),
country: "",
region: "",
coord: {
lon: longitude,
lat: latitude,
},
};

setSearchValue(city);
findCityByCoordinatesMutation.mutate({
coordinates: { lat: latitude, lng: longitude },
});
});
}
}}
>
{translationSearch("my city button")}
{translationSearch("my location button")}
</button>
{searchValue.name.length > 0 ? (
<button
Expand Down
2 changes: 2 additions & 0 deletions src/server/api/root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { weatherRouter } from "~/server/api/routers/weather";
import { createTRPCRouter } from "~/server/api/trpc";
import { emailRouter } from "~/server/api/routers/email";
import { searchRouter } from "~/server/api/routers/search";
import { reverseGeoRouter } from "~/server/api/routers/reverseGeo";

/**
* This is the primary router for your server.
Expand All @@ -12,6 +13,7 @@ export const appRouter = createTRPCRouter({
weather: weatherRouter,
email: emailRouter,
search: searchRouter,
reverseGeoRouter: reverseGeoRouter,
});

// export type definition of API
Expand Down
82 changes: 82 additions & 0 deletions src/server/api/routers/reverseGeo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { z } from "zod";
import { createTRPCRouter, rateLimitedProcedure } from "~/server/api/trpc";
import { env } from "~/env.mjs";
import axios from "axios";
import { log } from "next-axiom";
import { type ICity } from "~/types";
import crypto from "crypto";

const reverseGeoSchema = z.array(
z.object({
name: z.string(),
country: z.string(),
state: z.string().optional(),
}),
);

type ReverseGeo = z.infer<typeof reverseGeoSchema> | undefined;

function generateId(object: ReverseGeo): number {
const str = JSON.stringify(object);
const hash = crypto.createHash("md5").update(str).digest("hex");
return parseInt(hash.slice(0, 12), 16);
}

export const reverseGeoRouter = createTRPCRouter({
getCity: rateLimitedProcedure
.input(
z.object({
coordinates: z.object({
lat: z.number(),
lng: z.number(),
}),
}),
)
.mutation(async ({ input }): Promise<ICity | undefined> => {
log.info("User requested location data for coordinates", {
coordinates: input.coordinates,
});

const urlReverseGeo = `https://api.api-ninjas.com/v1/reversegeocoding?lat=${input.coordinates.lat.toString()}&lon=${input.coordinates.lng.toString()}`;

let reverseGeoData: ReverseGeo = undefined;

try {
const reverseGeoResult = await axios.get<ReverseGeo>(urlReverseGeo, {
headers: {
"X-Api-Key": `${env.API_NINJA_API_KEY}`,
},
});
/* log.debug("Reverse geocoding data", {
data: (reverseGeoResult).data,
}); */
reverseGeoData = reverseGeoSchema.parse(reverseGeoResult.data);
} catch (error) {
if (error instanceof z.ZodError) {
log.error("Zod Errors", error.issues);
} else {
log.error("Error while fetching reverse geocoding data", {
error: error,
});
}
}

// Return if no data
if (!reverseGeoData?.[0]) {
return undefined;
}

// console.log(generateId(reverseGeoData));

return {
id: generateId(reverseGeoData),
name: reverseGeoData[0].name,
coord: {
lat: input.coordinates.lat,
lon: input.coordinates.lng,
},
country: reverseGeoData[0].country,
region: reverseGeoData[0].state ?? "",
};
}),
});

1 comment on commit 55e9d81

@vercel
Copy link

@vercel vercel bot commented on 55e9d81 Jan 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.