diff --git a/.env.example b/.env.example
index 7247381..ef9af60 100644
--- a/.env.example
+++ b/.env.example
@@ -1,6 +1,6 @@
-REACT_APP_PUBLIC_URL=https://www.stiletto.live
-REACT_APP_RESOURCES_URL= URL API ADDRESS FOR ICONS AND MAPS
-REACT_APP_API_URL= URL API
-REACT_APP_DISCORD_CLIENT_ID= DISCORD CLIENT ID
-REACT_APP_GA_ID= Google Analytics ID
+REACT_APP_PUBLIC_URL=https://www.stiletto.live
+REACT_APP_RESOURCES_URL= URL API ADDRESS FOR ICONS AND MAPS
+REACT_APP_API_URL= URL API
+REACT_APP_DISCORD_CLIENT_ID= DISCORD CLIENT ID
+REACT_APP_PLAUSIBLE_URL=PLAUSIBLE URL
REACT_APP_VERSION=$npm_package_version
\ No newline at end of file
diff --git a/README.md b/README.md
index 55ce791..4925d57 100644
--- a/README.md
+++ b/README.md
@@ -44,7 +44,7 @@ The website uses several json files to read the game data so that it is always u
- REACT_APP_RESOURCES_URL= URL API ADDRESS FOR ICONS AND MAPS
- REACT_APP_API_URL= URL API
- REACT_APP_DISCORD_CLIENT_ID= DISCORD CLIENT ID
-- REACT_APP_GA_ID= Google Analytics ID
+- REACT_APP_PLAUSIBLE_URL=PLAUSIBLE URL
#### Generate maps
diff --git a/package.json b/package.json
index 803dcc6..8199180 100644
--- a/package.json
+++ b/package.json
@@ -1,80 +1,79 @@
-{
- "name": "stiletto-web",
- "version": "4.6.2",
- "license": "UNLICENSED",
- "author": "Dm94Dani",
- "description": "Web with different utilities for the game Last Oasis",
- "private": true,
- "bugs": {
- "url": "https://github.com/dm94/stiletto-web/issues"
- },
- "repository": {
- "type": "git",
- "url": "https://github.com/dm94/stiletto-web"
- },
- "dependencies": {
- "@giscus/react": "^2.2.6",
- "axios": ">=1.3.1",
- "beautiful-skill-tree": "^1.7.1",
- "bootstrap": "^4.5.3",
- "i18next": "^22.4.9",
- "i18next-browser-languagedetector": "^7.0.1",
- "i18next-http-backend": "^2.1.1",
- "jquery": "^3.6.3",
- "leaflet": "^1.7.1",
- "leaflet-rastercoords": "^1.0.5",
- "query-string": "^8.1.0",
- "react": "^16.14.0",
- "react-dom": "^16.14.0",
- "react-ga4": "^2.0.0",
- "react-helmet": "^6.1.0",
- "react-i18next": "^12.1.4",
- "react-leaflet": "^2.8.0",
- "react-router-dom": "^5.2.0",
- "react-scripts": "^5.0.1",
- "react-tiny-virtual-list": "^2.2.0",
- "workbox": "0.0.0",
- "workbox-core": "^6.5.4",
- "workbox-expiration": "^6.5.4",
- "workbox-precaching": "^6.5.4",
- "workbox-routing": "^6.5.4",
- "workbox-strategies": "^6.5.4"
- },
- "scripts": {
- "start": "react-scripts start",
- "build": "react-scripts build",
- "test": "react-scripts test",
- "eject": "react-scripts eject",
- "cypress": "cypress open",
- "cypress:test": "cypress run",
- "lint": "eslint --fix --ext .js,.jsx ."
- },
- "eslintConfig": {
- "extends": "react-app"
- },
- "browserslist": {
- "production": [
- ">0.2%",
- "not dead",
- "not op_mini all"
- ],
- "development": [
- "last 1 chrome version",
- "last 1 firefox version",
- "last 1 safari version"
- ]
- },
- "devDependencies": {
- "@babel/preset-react": "^7.18.6",
- "babel-eslint": "^10.1.0",
- "cypress": "^12.5.1",
- "eslint": "^8.33.0",
- "eslint-plugin-cypress": "^2.12.1",
- "eslint-plugin-prettier": "^4.2.1",
- "prettier": "^2.8.3"
- },
- "engines": {
- "node": "18.x"
- },
- "lint": "eslint --ext .js,.jsx ."
-}
+{
+ "name": "stiletto-web",
+ "version": "4.6.3",
+ "license": "UNLICENSED",
+ "author": "Dm94Dani",
+ "description": "Web with different utilities for the game Last Oasis",
+ "private": true,
+ "bugs": {
+ "url": "https://github.com/dm94/stiletto-web/issues"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/dm94/stiletto-web"
+ },
+ "dependencies": {
+ "@giscus/react": "^2.2.6",
+ "axios": ">=1.3.1",
+ "beautiful-skill-tree": "^1.7.1",
+ "bootstrap": "^4.5.3",
+ "i18next": "^22.4.9",
+ "i18next-browser-languagedetector": "^7.0.1",
+ "i18next-http-backend": "^2.1.1",
+ "jquery": "^3.6.3",
+ "leaflet": "^1.7.1",
+ "leaflet-rastercoords": "^1.0.5",
+ "query-string": "^8.1.0",
+ "react": "^16.14.0",
+ "react-dom": "^16.14.0",
+ "react-helmet": "^6.1.0",
+ "react-i18next": "^12.1.4",
+ "react-leaflet": "^2.8.0",
+ "react-router-dom": "^5.2.0",
+ "react-scripts": "^5.0.1",
+ "react-tiny-virtual-list": "^2.2.0",
+ "workbox": "0.0.0",
+ "workbox-core": "^6.5.4",
+ "workbox-expiration": "^6.5.4",
+ "workbox-precaching": "^6.5.4",
+ "workbox-routing": "^6.5.4",
+ "workbox-strategies": "^6.5.4"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject",
+ "cypress": "cypress open",
+ "cypress:test": "cypress run",
+ "lint": "eslint --fix --ext .js,.jsx ."
+ },
+ "eslintConfig": {
+ "extends": "react-app"
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ },
+ "devDependencies": {
+ "@babel/preset-react": "^7.18.6",
+ "babel-eslint": "^10.1.0",
+ "cypress": "^12.5.1",
+ "eslint": "^8.33.0",
+ "eslint-plugin-cypress": "^2.12.1",
+ "eslint-plugin-prettier": "^4.2.1",
+ "prettier": "^2.8.3"
+ },
+ "engines": {
+ "node": "18.x"
+ },
+ "lint": "eslint --ext .js,.jsx ."
+}
diff --git a/src/components/ChangeLanguageModal.jsx b/src/components/ChangeLanguageModal.jsx
index 78a58cb..f932e84 100644
--- a/src/components/ChangeLanguageModal.jsx
+++ b/src/components/ChangeLanguageModal.jsx
@@ -1,69 +1,68 @@
-import React, { Component } from "react";
-import { withTranslation } from "react-i18next";
-import { getStoredItem } from "../services";
-
-class ChangeLanguageModal extends Component {
- getLanguajes = () => {
- const supportedLanguages = [
- { key: "en", name: "English" },
- { key: "es", name: "Spanish" },
- { key: "ru", name: "Russian" },
- { key: "fr", name: "French" },
- { key: "de", name: "German" },
- { key: "it", name: "Italian" },
- { key: "ja", name: "Japanese" },
- { key: "pl", name: "Polish" },
- { key: "zh", name: "Chinese Simplified" },
- { key: "pt", name: "Portuguese, Brazilian" },
- { key: "uk", name: "Ukrainian" },
- ];
-
- return supportedLanguages.map((languaje) => {
- const { t } = this.props;
- return (
-
-
![{`${languaje.name}]({`/img/${languaje.key}.jpg`})
this.props.switchLanguage(languaje.key)}
- />
-
{t(languaje.name)}
-
- );
- });
- };
-
- render() {
- const { t } = this.props;
- return (
-
-
-
-
{t("Change language")}
-
-
{this.getLanguajes()}
-
-
-
v4.6.2
-
-
-
-
-
- );
- }
-}
-
-export default withTranslation()(ChangeLanguageModal);
+import React, { Component } from "react";
+import { withTranslation } from "react-i18next";
+import { getStoredItem } from "../services";
+
+class ChangeLanguageModal extends Component {
+ getLanguajes = () => {
+ const supportedLanguages = [
+ { key: "en", name: "English" },
+ { key: "es", name: "Spanish" },
+ { key: "ru", name: "Russian" },
+ { key: "fr", name: "French" },
+ { key: "de", name: "German" },
+ { key: "it", name: "Italian" },
+ { key: "ja", name: "Japanese" },
+ { key: "pl", name: "Polish" },
+ { key: "zh", name: "Chinese Simplified" },
+ { key: "pt", name: "Portuguese, Brazilian" },
+ { key: "uk", name: "Ukrainian" },
+ ];
+
+ return supportedLanguages.map((languaje) => {
+ const { t } = this.props;
+ return (
+
+
![{`${languaje.name}]({`/img/${languaje.key}.jpg`})
this.props.switchLanguage(languaje.key)}
+ />
+
{t(languaje.name)}
+
+ );
+ });
+ };
+
+ render() {
+ const { t } = this.props;
+ return (
+
+
+
+
{t("Change language")}
+
+
{this.getLanguajes()}
+
+
+
+
+
+
+
+ );
+ }
+}
+
+export default withTranslation()(ChangeLanguageModal);
diff --git a/src/components/Crafter/TotalMaterials.jsx b/src/components/Crafter/TotalMaterials.jsx
index 90a791b..e8de286 100644
--- a/src/components/Crafter/TotalMaterials.jsx
+++ b/src/components/Crafter/TotalMaterials.jsx
@@ -1,205 +1,208 @@
-import React, { Component } from "react";
-import { withTranslation } from "react-i18next";
-import Axios from "axios";
-import ListIngredients from "./ListIngredients";
-import Icon from "../Icon";
-import { sendEvent } from "../../page-tracking";
-import { sendNotification } from "../../functions/broadcast";
-
-class TotalMaterials extends Component {
- constructor(props) {
- super(props);
- this.state = {
- recipeToken: "",
- };
- }
-
- addRecipe = () => {
- sendEvent({
- category: "Share",
- action: "Generate a recipe code",
- });
- const items = this.props.selectedItems.map((item) => {
- return { name: item.name, count: item.count };
- });
- const options = {
- method: "post",
- url: process.env.REACT_APP_API_URL + "/recipes",
- params: {
- items: JSON.stringify(items),
- },
- };
-
- Axios.request(options)
- .then((response) => {
- if (response.status === 503) {
- sendNotification("Error connecting to database", "Error");
- } else if (response.status === 201) {
- sendNotification("Sharing code has been generated", "Information");
- this.setState({ recipeToken: response.data.token });
- }
- })
- .catch(() => {
- sendNotification("Error when connecting to the API", "Error");
- });
- };
-
- footerPart(t) {
- if (this.state.recipeToken.length > 0) {
- const url =
- window.location.protocol.concat("//").concat(window.location.hostname) +
- (window.location.port ? ":" + window.location.port : "") +
- "/crafter?recipe=" +
- this.state.recipeToken;
- return (
-
-
-
-
- {this.shareButton(t)}
-
-
- );
- } else {
- return this.shareButton(t);
- }
- }
-
- shareButton(t) {
- return (
-
- );
- }
-
- itemsList(t) {
- const http = window.location.protocol;
- const slashes = http.concat("//");
- const host = slashes.concat(window.location.hostname);
- const url =
- host +
- (window.location.port ? ":" + window.location.port : "") +
- "/item/";
-
- return this.props.selectedItems.map((item) => (
-
- {item.count}x{" "}
-
- {t(item.name, { ns: "items" })}
- {" "}
- -
-
- ));
- }
-
- copyMaterials = (t) => {
- sendEvent({
- category: "Share",
- action: "Copy materials",
- });
-
- let text = t("To make") + ":\n\n";
-
- this.props.selectedItems.forEach(
- (item) =>
- (text += item.count + "x " + t(item.name, { ns: "items" }) + " - ")
- );
-
- text += "\n\n" + t("You need the following materials") + ":\n\n";
-
- const totalIngredients = [];
- this.props.selectedItems.forEach((item) => {
- if (item.crafting != null && item.crafting[0].ingredients != null) {
- const output =
- item.crafting[0].output != null ? item.crafting[0].output : 1;
- item.crafting[0].ingredients.forEach((ingredient) => {
- if (
- totalIngredients.find((ingre) => ingre.name === ingredient.name)
- ) {
- totalIngredients.forEach((ingre) => {
- if (ingre.name === ingredient.name) {
- ingre.count += (ingredient.count / output) * item.count;
- }
- });
- } else {
- totalIngredients.push({
- name: ingredient.name,
- count: (ingredient.count / output) * item.count,
- ingredients: ingredient.ingredients,
- });
- }
- });
- }
- });
- totalIngredients.forEach(
- (ingredient) =>
- (text += "\t" + ingredient.count + "x " + t(ingredient.name) + "\n")
- );
-
- text +=
- "\n" +
- t("List of all necessary materials by") +
- " " +
- window.location.origin;
-
- navigator.clipboard.writeText(text);
- sendNotification("Items copied to the clipboard", "Information");
- };
-
- render() {
- const { t } = this.props;
- return (
-
-
-
-
{t("Total materials")}
-
-
-
-
-
-
- {t("List of all necessary materials by")}{" "}
- {window.location.hostname +
- (window.location.port ? ":" + window.location.port : "")}
-
-
-
-
{this.footerPart(t)}
-
- );
- }
-}
-export default withTranslation()(TotalMaterials);
+import React, { Component } from "react";
+import { withTranslation } from "react-i18next";
+import Axios from "axios";
+import ListIngredients from "./ListIngredients";
+import Icon from "../Icon";
+import { sendEvent } from "../../page-tracking";
+import { sendNotification } from "../../functions/broadcast";
+
+class TotalMaterials extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ recipeToken: "",
+ };
+ }
+
+ addRecipe = () => {
+ sendEvent("share", {
+ props: {
+ action: "addRecipe",
+ },
+ });
+
+ const items = this.props.selectedItems.map((item) => {
+ return { name: item.name, count: item.count };
+ });
+ const options = {
+ method: "post",
+ url: process.env.REACT_APP_API_URL + "/recipes",
+ params: {
+ items: JSON.stringify(items),
+ },
+ };
+
+ Axios.request(options)
+ .then((response) => {
+ if (response.status === 503) {
+ sendNotification("Error connecting to database", "Error");
+ } else if (response.status === 201) {
+ sendNotification("Sharing code has been generated", "Information");
+ this.setState({ recipeToken: response.data.token });
+ }
+ })
+ .catch(() => {
+ sendNotification("Error when connecting to the API", "Error");
+ });
+ };
+
+ footerPart(t) {
+ if (this.state.recipeToken.length > 0) {
+ const url =
+ window.location.protocol.concat("//").concat(window.location.hostname) +
+ (window.location.port ? ":" + window.location.port : "") +
+ "/crafter?recipe=" +
+ this.state.recipeToken;
+ return (
+
+
+
+
+ {this.shareButton(t)}
+
+
+ );
+ } else {
+ return this.shareButton(t);
+ }
+ }
+
+ shareButton(t) {
+ return (
+
+ );
+ }
+
+ itemsList(t) {
+ const http = window.location.protocol;
+ const slashes = http.concat("//");
+ const host = slashes.concat(window.location.hostname);
+ const url =
+ host +
+ (window.location.port ? ":" + window.location.port : "") +
+ "/item/";
+
+ return this.props.selectedItems.map((item) => (
+
+ {item.count}x{" "}
+
+ {t(item.name, { ns: "items" })}
+ {" "}
+ -
+
+ ));
+ }
+
+ copyMaterials = (t) => {
+ sendEvent("share", {
+ props: {
+ action: "copyMaterials",
+ },
+ });
+
+ let text = t("To make") + ":\n\n";
+
+ this.props.selectedItems.forEach(
+ (item) =>
+ (text += item.count + "x " + t(item.name, { ns: "items" }) + " - ")
+ );
+
+ text += "\n\n" + t("You need the following materials") + ":\n\n";
+
+ const totalIngredients = [];
+ this.props.selectedItems.forEach((item) => {
+ if (item.crafting != null && item.crafting[0].ingredients != null) {
+ const output =
+ item.crafting[0].output != null ? item.crafting[0].output : 1;
+ item.crafting[0].ingredients.forEach((ingredient) => {
+ if (
+ totalIngredients.find((ingre) => ingre.name === ingredient.name)
+ ) {
+ totalIngredients.forEach((ingre) => {
+ if (ingre.name === ingredient.name) {
+ ingre.count += (ingredient.count / output) * item.count;
+ }
+ });
+ } else {
+ totalIngredients.push({
+ name: ingredient.name,
+ count: (ingredient.count / output) * item.count,
+ ingredients: ingredient.ingredients,
+ });
+ }
+ });
+ }
+ });
+ totalIngredients.forEach(
+ (ingredient) =>
+ (text += "\t" + ingredient.count + "x " + t(ingredient.name) + "\n")
+ );
+
+ text +=
+ "\n" +
+ t("List of all necessary materials by") +
+ " " +
+ window.location.origin;
+
+ navigator.clipboard.writeText(text);
+ sendNotification("Items copied to the clipboard", "Information");
+ };
+
+ render() {
+ const { t } = this.props;
+ return (
+
+
+
+
{t("Total materials")}
+
+
+
+
+
+
+ {t("List of all necessary materials by")}{" "}
+ {window.location.hostname +
+ (window.location.port ? ":" + window.location.port : "")}
+
+
+
+
{this.footerPart(t)}
+
+ );
+ }
+}
+export default withTranslation()(TotalMaterials);
diff --git a/src/components/ModalMessage.jsx b/src/components/ModalMessage.jsx
index 61d1056..283bc05 100644
--- a/src/components/ModalMessage.jsx
+++ b/src/components/ModalMessage.jsx
@@ -1,76 +1,75 @@
-import React, { Component } from "react";
-import { Redirect } from "react-router-dom";
-import { withTranslation } from "react-i18next";
-import { sendEvent } from "../page-tracking";
-
-class ModalMessage extends Component {
- state = { redirect: false };
-
- redirectButton() {
- return (
-
- );
- }
-
- onlyOkButton() {
- return (
-
- );
- }
-
- render() {
- const { t } = this.props;
- if (this.props.message.text === "Error when connecting to the API") {
- localStorage.removeItem("allItems");
- sessionStorage.removeItem("allItems");
- caches.keys().then((names) => {
- for (const name of names) {
- caches.delete(name);
- }
- });
- }
- if (this.state.redirect) {
- return ;
- }
-
- console.log(t(this.props.message.text));
- sendEvent({
- category: "Modal",
- action: this.props.message.isError ? "Error" : "Information",
- label: this.props.message.text,
- nonInteraction: true,
- });
-
- return (
-
-
-
-
-
- {this.props.message.isError ? t("Error") : t("Information")}
-
-
-
{t(this.props.message.text)}
-
- {this.props.message.redirectPage == null
- ? this.onlyOkButton()
- : this.redirectButton()}
-
-
-
-
- );
- }
-}
-
-export default withTranslation()(ModalMessage);
+import React, { Component } from "react";
+import { Redirect } from "react-router-dom";
+import { withTranslation } from "react-i18next";
+import { sendEvent } from "../page-tracking";
+
+class ModalMessage extends Component {
+ state = { redirect: false };
+
+ redirectButton() {
+ return (
+
+ );
+ }
+
+ onlyOkButton() {
+ return (
+
+ );
+ }
+
+ render() {
+ const { t } = this.props;
+ if (this.props.message.text === "Error when connecting to the API") {
+ localStorage.removeItem("allItems");
+ sessionStorage.removeItem("allItems");
+ caches.keys().then((names) => {
+ for (const name of names) {
+ caches.delete(name);
+ }
+ });
+ }
+ if (this.state.redirect) {
+ return ;
+ }
+
+ sendEvent("modal", {
+ props: {
+ action: this.props?.message?.isError ? "Error" : "Information",
+ label: this.props?.message?.text,
+ },
+ });
+
+ return (
+
+
+
+
+
+ {this.props.message.isError ? t("Error") : t("Information")}
+
+
+
{t(this.props.message.text)}
+
+ {this.props.message.redirectPage == null
+ ? this.onlyOkButton()
+ : this.redirectButton()}
+
+
+
+
+ );
+ }
+}
+
+export default withTranslation()(ModalMessage);
diff --git a/src/page-tracking.js b/src/page-tracking.js
index db1f883..afe5685 100644
--- a/src/page-tracking.js
+++ b/src/page-tracking.js
@@ -1,31 +1,45 @@
-import { useEffect, useState } from "react";
-import { useLocation } from "react-router-dom";
-import ReactGA from "react-ga4";
-
-export const usePageTracking = () => {
- const location = useLocation();
- const [initialized, setInitialized] = useState(false);
-
- useEffect(() => {
- if (localStorage.getItem("acceptscookies") && process.env.REACT_APP_GA_ID) {
- ReactGA.initialize(process.env.REACT_APP_GA_ID);
- }
- setInitialized(true);
- }, []);
-
- useEffect(() => {
- if (
- localStorage.getItem("acceptscookies") &&
- process.env.REACT_APP_GA_ID &&
- initialized
- ) {
- ReactGA.send({ hitType: "pageview", page: location.pathname });
- }
- }, [initialized, location]);
-};
-
-export const sendEvent = (data) => {
- if (localStorage.getItem("acceptscookies") && process.env.REACT_APP_GA_ID) {
- ReactGA.event(data);
- }
-};
+import { useEffect } from "react";
+import { useLocation } from "react-router-dom";
+
+export const initPlausible = () => {
+ const PLAUSIBLE_URL = process.env.REACT_APP_PLAUSIBLE_URL;
+
+ if (!PLAUSIBLE_URL || PLAUSIBLE_URL.length <= 0) {
+ return;
+ }
+
+ const script = document.querySelector(`script[src*="${PLAUSIBLE_URL}"]`);
+ if (script) {
+ return;
+ }
+
+ const element = document.createElement("script");
+ element.src = PLAUSIBLE_URL;
+ element.defer = true;
+ element.setAttribute("data-domain", document.location.hostname);
+ document.head.appendChild(element);
+};
+
+export const usePageTracking = () => {
+ const location = useLocation();
+
+ useEffect(() => {
+ initPlausible();
+ }, []);
+
+ useEffect(() => {
+ initPlausible();
+ }, [location]);
+};
+
+export const sendEvent = (data) => {
+ initPlausible();
+
+ window.plausible =
+ window.plausible ||
+ function() {
+ (window.plausible.q = window.plausible.q || []).push(arguments);
+ };
+
+ window.plausible(...data);
+};
diff --git a/src/pages/Wiki.jsx b/src/pages/Wiki.jsx
index a4d4026..42211eb 100644
--- a/src/pages/Wiki.jsx
+++ b/src/pages/Wiki.jsx
@@ -1,215 +1,217 @@
-import React, { Component } from "react";
-import { withTranslation } from "react-i18next";
-import { Helmet } from "react-helmet";
-import queryString from "query-string";
-import { getItems } from "../services";
-import { sendEvent } from "../page-tracking";
-import Ingredient from "../components/Ingredient";
-
-class Wiki extends Component {
- constructor(props) {
- super(props);
- this.state = {
- items: [],
- searchText: "",
- textSearched: "",
- filteredItems: [],
- error: "",
- categories: [],
- categoryFilter: "All",
- };
- }
-
- componentDidMount() {
- this.updateRecipes();
- let parsed = null;
- if (this.props.location != null && this.props.location.search != null) {
- parsed = queryString.parse(this.props.location.search);
- }
- if (parsed && parsed.s != null) {
- this.setState({ searchText: parsed.s }, () => this.searchItems());
- }
- }
-
- updateRecipes = async () => {
- const items = await getItems();
- if (items != null) {
- const allCategories = [];
-
- items.forEach((item) => {
- if (item.category && !allCategories.includes(item.category)) {
- allCategories.push(item.category);
- }
- });
- allCategories.sort();
-
- this.setState({ items: items, categories: allCategories });
- }
- };
-
- searchItems = async () => {
- const search = this.state.searchText;
- sendEvent({
- category: "User",
- action: "Wiki search",
- label: search,
- });
- if (this.state.items == null || this.state.items.length <= 0) {
- await this.updateRecipes();
- }
- const { t } = this.props;
- let filteredItems = this.state.items;
-
- if (this.state.categoryFilter && this.state.categoryFilter !== "All") {
- filteredItems = filteredItems.filter((item) => {
- return item.category && item.category === this.state.categoryFilter;
- });
- }
-
- filteredItems = filteredItems.filter((it) => {
- return search.split(" ").every((internalItem) => {
- return (
- t(it.name).toLowerCase().indexOf(internalItem.toLowerCase()) !== -1
- );
- });
- });
- this.setState({
- filteredItems: filteredItems,
- textSearched: search,
- });
- };
-
- showItems = (t) => {
- if (this.state.filteredItems != null) {
- if (this.state.filteredItems.length > 0) {
- return this.state.filteredItems.map((item) => (
-
-
-
- ));
- } else if (this.state.textSearched.length > 0) {
- return (
-
-
-
- {t("Nothing found")}
-
-
-
- );
- }
- }
- };
-
- showCategories = (t) => {
- if (this.state.categories != null && this.state.categories.length > 0) {
- return this.state.categories.map((category) => (
-
- ));
- }
- };
-
- render() {
- const { t } = this.props;
-
- return (
-
-
- Last Oasis Wiki - Stiletto
-
-
-
-
-
-
-
-
-
-
-
-
- this.setState({ searchText: e.currentTarget.value })
- }
- onKeyPress={(e) => {
- const keyPress = e.key || e.keyCode;
- if (keyPress === 13 || keyPress === "Enter") {
- this.searchItems();
- }
- }}
- value={this.state.searchText}
- />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- }
-}
-
-export default withTranslation()(Wiki);
+import React, { Component } from "react";
+import { withTranslation } from "react-i18next";
+import { Helmet } from "react-helmet";
+import queryString from "query-string";
+import { getItems } from "../services";
+import { sendEvent } from "../page-tracking";
+import Ingredient from "../components/Ingredient";
+
+class Wiki extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ items: [],
+ searchText: "",
+ textSearched: "",
+ filteredItems: [],
+ error: "",
+ categories: [],
+ categoryFilter: "All",
+ };
+ }
+
+ componentDidMount() {
+ this.updateRecipes();
+ let parsed = null;
+ if (this.props.location != null && this.props.location.search != null) {
+ parsed = queryString.parse(this.props.location.search);
+ }
+ if (parsed && parsed.s != null) {
+ this.setState({ searchText: parsed.s }, () => this.searchItems());
+ }
+ }
+
+ updateRecipes = async () => {
+ const items = await getItems();
+ if (items != null) {
+ const allCategories = [];
+
+ items.forEach((item) => {
+ if (item.category && !allCategories.includes(item.category)) {
+ allCategories.push(item.category);
+ }
+ });
+ allCategories.sort();
+
+ this.setState({ items: items, categories: allCategories });
+ }
+ };
+
+ searchItems = async () => {
+ const search = this.state.searchText;
+
+ sendEvent("search", {
+ props: {
+ term: search,
+ },
+ });
+
+ if (this.state.items == null || this.state.items.length <= 0) {
+ await this.updateRecipes();
+ }
+ const { t } = this.props;
+ let filteredItems = this.state.items;
+
+ if (this.state.categoryFilter && this.state.categoryFilter !== "All") {
+ filteredItems = filteredItems.filter((item) => {
+ return item.category && item.category === this.state.categoryFilter;
+ });
+ }
+
+ filteredItems = filteredItems.filter((it) => {
+ return search.split(" ").every((internalItem) => {
+ return (
+ t(it.name).toLowerCase().indexOf(internalItem.toLowerCase()) !== -1
+ );
+ });
+ });
+ this.setState({
+ filteredItems: filteredItems,
+ textSearched: search,
+ });
+ };
+
+ showItems = (t) => {
+ if (this.state.filteredItems != null) {
+ if (this.state.filteredItems.length > 0) {
+ return this.state.filteredItems.map((item) => (
+
+
+
+ ));
+ } else if (this.state.textSearched.length > 0) {
+ return (
+
+
+
+ {t("Nothing found")}
+
+
+
+ );
+ }
+ }
+ };
+
+ showCategories = (t) => {
+ if (this.state.categories != null && this.state.categories.length > 0) {
+ return this.state.categories.map((category) => (
+
+ ));
+ }
+ };
+
+ render() {
+ const { t } = this.props;
+
+ return (
+
+
+ Last Oasis Wiki - Stiletto
+
+
+
+
+
+
+
+
+
+
+
+
+ this.setState({ searchText: e.currentTarget.value })
+ }
+ onKeyPress={(e) => {
+ const keyPress = e.key || e.keyCode;
+ if (keyPress === 13 || keyPress === "Enter") {
+ this.searchItems();
+ }
+ }}
+ value={this.state.searchText}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+export default withTranslation()(Wiki);