From 3060c429e25d74e622d4b54885691937b6837bcb Mon Sep 17 00:00:00 2001 From: Shri Hari L <57325503+shrihari689@users.noreply.github.com> Date: Sat, 8 May 2021 14:53:03 +0530 Subject: [PATCH 1/6] =?UTF-8?q?=F0=9F=9A=80=20Add=20StateHome=20Component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/StateHome.jsx | 9 +++++++++ pages/[state]/index.js | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 components/StateHome.jsx diff --git a/components/StateHome.jsx b/components/StateHome.jsx new file mode 100644 index 000000000..138757bcc --- /dev/null +++ b/components/StateHome.jsx @@ -0,0 +1,9 @@ +import React from 'react'; + +const StateHome = () => { + return ( +
+ ); +} + +export default StateHome; \ No newline at end of file diff --git a/pages/[state]/index.js b/pages/[state]/index.js index b71fe3cc7..dd0d88827 100644 --- a/pages/[state]/index.js +++ b/pages/[state]/index.js @@ -1,8 +1,8 @@ import React from 'react'; import { parametreize, statesStaticPaths, humanize } from '@lib/utils'; import { NextSeo } from 'next-seo'; -import DetailedHome from '@components/DetailedHome'; import { useRouter } from 'next/router'; +import StateHome from '@components/StateHome'; export default function State({ state }) { const SEO = { @@ -28,7 +28,7 @@ export default function State({ state }) { return ( <> - + ); } From 516cb780fdb7959c12abc68d0a4792ce9213e3a3 Mon Sep 17 00:00:00 2001 From: Shri Hari L <57325503+shrihari689@users.noreply.github.com> Date: Sat, 8 May 2021 19:47:08 +0530 Subject: [PATCH 2/6] =?UTF-8?q?=F0=9F=9A=80=20Add=20Suggestions=20for=20St?= =?UTF-8?q?ateHome?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/search.js | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/lib/search.js b/lib/search.js index 4a730b9b8..8ba441af3 100644 --- a/lib/search.js +++ b/lib/search.js @@ -1,4 +1,5 @@ import states from '@data/states.json'; +import resourceStats from "@data/resource_stats_v2.json" import topTenStatesAndDistricts from "@data/top_states_and_districts" export const getAllStateNames = () => { @@ -25,7 +26,7 @@ export const getAllDistrictNames = () => { }; export const getSuggestedWord = searchText => { - if (!searchText) return ""; + if (!searchText) return { displayText: "" }; const states = getAllStateNames(); const districts = getAllDistrictNames(); const stateSuggestion = states.find(e => isExactMatch(e, searchText)); @@ -74,3 +75,44 @@ export const getSuggestedList = searchText => { export const isTrendingPlace = name => { return topTenStatesAndDistricts.find(e => e.name === name); }; + +export const getStatsByState = (state) => { + const data = resourceStats.states?.find(e => e.name === state && e.type === "State"); + return data || {} +} + +export const getSuggestedWordByState = (searchText, state) => { + if (!searchText) return { displayText: "" }; + const allDistricts = resourceStats.districts.filter(e => e.state === state); + const districtSuggestion = allDistricts.find(e => isExactMatch(e, searchText)); + if (districtSuggestion) { + const word = { + ...districtSuggestion, + displayText: + searchText + + districtSuggestion.name?.substring( + searchText.length, + districtSuggestion.length + ) + }; + return word; + } + return { displayText: "" }; +}; + +export const getSuggestedListByState = (searchText, state, type) => { + const RESULT_LIMIT = 10; + + const allDistricts = resourceStats.districts.filter(e => e.state === state); + + type = type === "All" ? "total" : type?.toLowerCase() + + if (!searchText) + return allDistricts?.sort((a, b) => a[type] > b[type]).slice(0, RESULT_LIMIT); + + const districts = allDistricts.filter(e => isPartialMatch(e, searchText)); + + return districts + .sort((a, _) => (isTrendingPlace(a.name) || isExactMatch(a, searchText) ? -1 : 0)) + .slice(0, RESULT_LIMIT); +}; From 97d2e61dc95e2a88b3e5f0dc64a37750f3346d84 Mon Sep 17 00:00:00 2001 From: Shri Hari L <57325503+shrihari689@users.noreply.github.com> Date: Sat, 8 May 2021 19:50:06 +0530 Subject: [PATCH 3/6] =?UTF-8?q?=F0=9F=90=9B=20Make=20StateHome=20work=20mi?= =?UTF-8?q?nimal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/StateHome.jsx | 72 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/components/StateHome.jsx b/components/StateHome.jsx index 138757bcc..145c90860 100644 --- a/components/StateHome.jsx +++ b/components/StateHome.jsx @@ -1,8 +1,74 @@ -import React from 'react'; +import { faCheckCircle, faFire, faGlobeAsia } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { statesAndDistrict } from '@lib/api'; +import { getStatsByState } from '@lib/search'; +import React, { useState } from 'react'; +import { resources } from './search/SearchIntro'; +import StateSearchField from './search/StateSearchField'; + +const StateHome = ({ state, type }) => { + + const [resource, setResource] = useState(type || "All") + + const statesWithDistricts = statesAndDistrict(); + const states = Object.keys(statesWithDistricts); + state = states.find((e) => e.toLowerCase() === state?.toLowerCase()); + + const stats = getStatsByState(state) + + const resourceListing = [ + { name: "All", icon: faGlobeAsia, count: stats["total"], verified: stats["verified"] }, + ...resources.map(e => ({ ...e, count: stats[e.name.toLowerCase()], verified: stats[`${e.name.toLowerCase()}_verified`] })) + ]; -const StateHome = () => { return ( -
+
+

+ Resources in {state} +

+
+ +
+

+ Overview +

+
+ { + resourceListing.map(({ name, icon, verified, count }) => { + return ( +
+
+ + + + {name} +
+
+
+ + + + Available: + {count} +
+
+ + + + Verified: + {verified} +
+
+
+ ) + }) + } +
+
); } From 9b823b156158a27f8c0307baee653e987134af41 Mon Sep 17 00:00:00 2001 From: Shri Hari L <57325503+shrihari689@users.noreply.github.com> Date: Sat, 8 May 2021 19:51:18 +0530 Subject: [PATCH 4/6] =?UTF-8?q?=F0=9F=94=8D=20Add=20a=20Separate=20Search?= =?UTF-8?q?=20Field?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/search/StateSearchField.jsx | 141 +++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 components/search/StateSearchField.jsx diff --git a/components/search/StateSearchField.jsx b/components/search/StateSearchField.jsx new file mode 100644 index 000000000..6a2b3304d --- /dev/null +++ b/components/search/StateSearchField.jsx @@ -0,0 +1,141 @@ +import React, { useState, createRef } from "react"; +import { isTrendingPlace, getSuggestedListByState, getSuggestedWordByState } from "@lib/search"; +import TrendingIcon from "@components/icons/TrendingIcon"; +import { useRouter } from "next/router"; +import { parametreize } from "@lib/utils"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faCog, faGlobeAsia, faTimes } from "@fortawesome/free-solid-svg-icons"; +import { resources } from "./SearchIntro"; + +const StateSearchField = ({ resource, setResource, state }) => { + const [searchText, setSearchText] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const [isFocus, onFocus] = useState(false); + const suggestionText = getSuggestedWordByState(searchText, state); + const suggestedResults = getSuggestedListByState(searchText, state, resource); + const searchFieldRef = createRef(); + const pageRouter = useRouter(); + + const handleSearchKeyDown = e => { + if (e.key === "Tab") { + e.preventDefault(); + if (suggestionText.name) { + setSearchText(suggestionText.name); + } + } else if (e.key === "Escape") { + e.preventDefault(); + searchFieldRef.current?.blur(); + } else if (e.key === "Enter" && suggestionText?.name) { + handleGotoResource(suggestionText) + } + }; + + const handleGotoResource = (result) => { + setIsLoading(true); + setSearchText(result.name); + const { name, type, state } = result; + if (type === "District") { + pageRouter.push( + `/${parametreize(state)}/${parametreize(name)}/${parametreize(resource)}` + ) + } + else if (type === "State") { + pageRouter.push(`/${parametreize(name)}/?resource=${resource}`) + } + + } + + const handleTabChange = (name) => { + setResource(name) + setTimeout(() => { + document.getElementById("searchField")?.focus(); + }, 500) + } + + return ( +
+
+ {[{ name: "All", icon: faGlobeAsia }, ...resources].map(({ name, icon }) => +
handleTabChange(name)} + className={"flex items-center cursor-pointer dark:text-gray-500 px-2 pt-1 border-primary-600 pb-1 text-center" + (name === resource ? " border-b-2 dark:text-primary-500 text-indigo-800" : "")} + key={name}> + + {name} +
+ )} +
+
+ + onFocus(true)} + onChange={({ target: { value } }) => setSearchText(value)} + onBlur={_ => { + setTimeout(() => { + onFocus(false); + }, 200) + }} + value={searchText} + type="text" + className="p-4 pl-6 text-base md:text-xl transition-shadow duration-300 ease-in-out shadow-md hover:shadow-lg focus:shadow-xl placeholder-gray-600 dark:text-white rounded-xl z-10 outline-none w-full absolute top-0 left-0 bg-transparent" + placeholder={`Search for districts with ${resource} resources`} + /> + {/* I am using Custom Close Icon instead of input[type='search'] to use dark style */} + { + (searchText && !isLoading) && + setSearchText("")}> + + + } + {/* Loading Icon when the user makes use of suggestions */} + { + isLoading && + setSearchText("")}> + + + } +
+ {isFocus && ( +
+

+ {!suggestedResults.length + ? "We couldn't find suggestions for you.. 💤" + : "Suggestions ⚡"} +

+
    + {suggestedResults.map((result, id) => ( +
  • handleGotoResource(result)} + className="py-2 px-1 flex mt-1 bg-gray-200 dark:bg-gray-1200 hover:bg-gray-300 dark:hover:bg-gray-1000 cursor-pointer rounded-lg items-center justify-between"> +
    + {isTrendingPlace(result.name) && ( + + )} + + {result.name} + +
    + + {result.state || result.type} + +
  • + ))} +
+
+ )} +
+ ); +}; +export default StateSearchField; From 4c83037ed0096045b339914f5c53a7e12e29e94d Mon Sep 17 00:00:00 2001 From: Shri Hari L <57325503+shrihari689@users.noreply.github.com> Date: Sat, 8 May 2021 19:54:48 +0530 Subject: [PATCH 5/6] =?UTF-8?q?=F0=9F=9A=80=20Add=20All=20to=20Resource=20?= =?UTF-8?q?Types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/search/SearchField.jsx | 6 +++--- pages/index.jsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/search/SearchField.jsx b/components/search/SearchField.jsx index 1e30a6021..6b9401753 100644 --- a/components/search/SearchField.jsx +++ b/components/search/SearchField.jsx @@ -6,7 +6,7 @@ import PulseIcon from "@components/icons/PulseIcon"; import { useRouter } from "next/router"; import { parametreize } from "@lib/utils"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faCog, faTimes } from "@fortawesome/free-solid-svg-icons"; +import { faCog, faGlobeAsia, faTimes } from "@fortawesome/free-solid-svg-icons"; import { faTwitter } from "@fortawesome/free-brands-svg-icons"; import { resources } from "./SearchIntro"; @@ -58,7 +58,7 @@ const SearchField = ({ isFocus, onFocus, resource, setResource }) => { return (
- {resources.map(({ name, icon }) => + {[{ name: "All", icon: faGlobeAsia }, ...resources].map(({ name, icon }) =>
handleTabChange(name)} className={"cursor-pointer dark:text-gray-500 px-2 pt-1 border-primary-600 pb-1 text-center" + (name === resource ? " border-b-2 dark:text-primary-500 text-indigo-800" : "")} @@ -91,7 +91,7 @@ const SearchField = ({ isFocus, onFocus, resource, setResource }) => { value={searchText} type="text" className="p-4 pl-6 text-base md:text-xl transition-shadow duration-300 ease-in-out shadow-md hover:shadow-lg focus:shadow-xl placeholder-gray-600 dark:text-white rounded-xl z-10 outline-none w-full absolute top-0 left-0 bg-transparent" - placeholder={`Search for ${resource} in States or Districts`} + placeholder={`Search for ${resource} resources in States or Districts`} /> { !searchText && diff --git a/pages/index.jsx b/pages/index.jsx index 26cdc0b8c..20713d168 100644 --- a/pages/index.jsx +++ b/pages/index.jsx @@ -15,7 +15,7 @@ export default function Home() { const { locale } = useLocaleContext(); const t = useLocale(locale, 'home'); - const [resource, setResource] = useState("Oxygen"); + const [resource, setResource] = useState("All"); const [isToShowSuggestion, setIsToShowSuggestion] = useState(false); return ( From d0ba2ba53d9a648108cc4fd1bb68132929d08eb2 Mon Sep 17 00:00:00 2001 From: Shri Hari L <57325503+shrihari689@users.noreply.github.com> Date: Thu, 13 May 2021 20:59:14 +0530 Subject: [PATCH 6/6] =?UTF-8?q?=F0=9F=92=B3=20Add=20Source=20Name=20to=20R?= =?UTF-8?q?esource=20Card?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/ResourceCard.jsx | 38 +++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/components/ResourceCard.jsx b/components/ResourceCard.jsx index d341120b5..ab650691f 100644 --- a/components/ResourceCard.jsx +++ b/components/ResourceCard.jsx @@ -8,7 +8,6 @@ import { useRouter } from 'next/router'; import { getHaversineDistance } from '@lib/utils'; import Badge from './Badge'; import Description from './Description'; - import FeedbackCounter from './FeedbackCounter'; const ResourceCard = ({ data, type: filterType, currentLocation }) => { @@ -21,7 +20,7 @@ const ResourceCard = ({ data, type: filterType, currentLocation }) => { // Metadata const { external_id: id, last_verified_on, verification_status } = data; - const { upvotes, downvotes } = data; + const { upvotes, downvotes, data_name } = data; // Oxygen Related Data const { quantity_available, price } = data; @@ -43,7 +42,7 @@ const ResourceCard = ({ data, type: filterType, currentLocation }) => { const category = `${type}` + (resource_type ? ` - ${resource_type}` : '') - const directions = getGoogleMapsDirectionLink(latitude,longitude); + const directions = getGoogleMapsDirectionLink(latitude, longitude); return (
@@ -64,7 +63,7 @@ const ResourceCard = ({ data, type: filterType, currentLocation }) => {
{district} - { directions.length > 0 && + {directions.length > 0 &&
} { - source_link && -
+
- Source + { + source_link ? + {data_name} + : {data_name} + }
}
@@ -191,18 +193,18 @@ const ResourceCard = ({ data, type: filterType, currentLocation }) => { {/* */}
- { currentLocation && latitude && longitude && ( - - Approximately - -  {getHaversineDistance(currentLocation, { - lat: latitude, - lng: longitude - })} Kms + {currentLocation && latitude && longitude && ( + + Approximately + +  {getHaversineDistance(currentLocation, { + lat: latitude, + lng: longitude + })} Kms + +  from your location -  from your location - - )} + )}