Skip to content

09. Further Customizing

Derick M edited this page Aug 22, 2023 · 2 revisions

In the sections below are details about how you can further customize ReactMap in a git friendly way.

Client Side Custom Code Injection

  • Don't like my implementation?
  • Too lazy to write a configurable PR?
  • Want to maintain custom files while keeping it git friendly?

You have the ability to replace every single file in the root src folder with your own implementation!

For example, if you want to customize the Pokestop marker:

  1. Copy src/components/markers/pokestop.jsx
  2. Name new file to src/components/markers/pokestop.custom.jsx
  3. Make your changes
  4. Recompile
  5. Celebrate that you're no longer limited to my opinions and praise how generous I am

F.A.Q. Q. But Turtle, why would I want to write a custom component instead of relying on the config?

  • The config is massive and overwhelming at this point. Most of the options only cater to a small handful of people.
  • We all have opinions, just write your own code, please leave me alone.
  • Performance. All of these unnecessary calculations for things like icon placement starts to impact performance when multiplying it by thousands.

Q. What do you mean this will never be officially supported?

  • If you are writing custom files, it is imperative that you keep an eye on PRs to make sure that they don't break your custom implementations.
  • I will not provide help with your custom implementations.

Q. How can you rudely break my custom component if it's git friendly?

  • Custom components still rely on the props being passed through, using the example above:
export default function pokestopMarker(pokestop, hasQuest, hasLure, hasInvasion, filters, Icons, userSettings)
  • You are still reliant on me passing all of these properties to the Pokestop marker, even in your custom implementation. If the inputs change, you must adjust your custom components.
  • I will do my best to inform people of changes that can affect custom components

Q. What files can I edit?

  • Any .css, .js, or .jsx file in the root src folder. This PR does not apply to files in the server or public folders.

Q. How does this inject custom code while maintaining git friendly-ness??

  • All files with the .custom.[js,jsx,css] ending are git ignored. The compiler checks if a custom file exists during the loading process, if it does, it replaces the contents of the standard file with the custom. Maintaining the original in the file structure while loading your custom file into the end bundle. Magic.

Server API Endpoints

An example of a custom API endpoint that can be used to fetch PVP cache stats:

  • You can create an unlimited number of git friendly, endpoints. They will stay git friendly as long as the main repo doesn't add a file of the same name at some point
  • You would add this by placing a new file with the below contents in server/src/routes/api/v1/
  • Whatever you name the file, becomes the endpoint, so cacheStats.js would become https://www.your-map-url.com/api/v1/cacheStats
  • You should set your ReactMap Secret in your config, but you can create them without secret authentication if you'd like
  • Example curl script curl -H "react-map-secret: your_secret" https://www.your-map-url.com/api/v1/stats/api/v1/cacheStats
const router = require('express').Router()
const { api } = require('../../../services/config')
const { Pvp } = require('../../../services/initialization')

router.get('/', async (req, res) => {
  try {
    if (api.reactMapSecret && req.headers['react-map-secret'] === api.reactMapSecret) {
      res.status(200).json(Pvp.rmCache.getStats())
    } else {
      throw new Error('Incorrect or missing API secret')
    }
    console.log('[API] api/v1/cache')
  } catch (e) {
    console.error('[API Error] api/v1/cache/', e)
    res.status(500).json({ status: 'ServerError', reason: e.message })
  }
})

module.exports = router

Page Generation via Config

The following settings apply to in your config:

  • Message of the Day
  • Donor Page
  • Login Page

You can add one time MotD's for your community to see upon opening the map from your config. Simply increment the index to make sure your users see the latest message, then add an many messages/components as you want in the message array. It accepts an array of strings or objects that have title, body, and footer properties, all are optional. The map will display all messages in the components array, so you'll need to clear old ones out if you don't wish for them to display.

Basic

  "messageOfTheDay": {
    "index": 1,
    "components": [
      {
        "title": "Title 1",
        "body": "Body 1",
        "footer": "Footer 1"
      },
      {
        "title": "Title 2",
        "body": "Body 2"
      },
      {
        "footer": "Footer 3"
      },
      "I am a boring message"
    ]
  }

Advanced

The advanced MoTD allows you to customize the message entirely using Material UI Components:

  • Each component you add into the components array, is wrapped in a Grid component. You set the grid sizes for each of these. A full row is 12 units. Read more about it here.

Components available:

  • Typography (type: text)
  • Divider (type: divider)
  • Button (type: button)
  • Standard html img tag (type: image)
  • Discord, Telegram, and Local login components
  • If you set the type to "parent", it creates a parent grid, which you can then populate with children components.

Styling:

    "messageOfTheDay": {
      "index": 2,
      "settings": {
  // Shows the MoTD every time upon login
        "permanent": true,
  // These are properties for the parent Grid component
        "parentSpacing": 0,
  // https://v4.mui.com/components/grid/#spacing
        "parentAlignContent": "center",
  // https://v4.mui.com/components/grid/#interactive
        "parentJustifyContent": "center",
  // CSS Properties in a JS Object, see below for examples
        "parentStyle": {},
  // Show MotD to non-donors only if true
        "freeloaderOnly": false,
  // Show MotD to donors only if true
        "donorOnly": false
  // Setting both to false will show to all
      },
      "titles": ["title1", "title2"],
      "components": [
  // Add an unlimited number of blocks here
        {
          "type": "button",
  // Size of the grid for the button
          "gridSizes": {
            "xs": 12,
            "sm": 6,
            "md": 4,
            "lg": 6,
            "xl": 3
          },
  // Styling for the grid itself
          "gridStyle": {
            "padding": 10
          },
  // Decides if it should only show to users who have the donor perm (set in config)
          "donorOnly": true,
  // Decides if it should only show to users who do not have the donor perm
  // Leave both false to show to everyone
  // Setting both to true will show to no one 
          "freeloaderOnly": false,
  // Choose a size
          "size": "small/medium/large",
          "variant": "contained/outlined/text",
  // Choose a color or set a CSS color (hexcode, color name, etc)
          "color": "primary/secondary/#353245",
  // The actual text to display on the button
          "content": "Button Text",
  // Link for the button
          "link": "https://www.github.com",
  // Styling for the button, CSS properties in a JS Object
          "style": {
            "textAlign": "center",
            "backgroundColor": "white",
            "color": "black",
            "margin": "10px 20px",
            "otherCssProperties": "5px"
          }
        },
        {
  // Normal Text
          "type": "text",
          "gridSizes": {
            "xs": 12,
            "sm": 6,
            "md": 4,
            "lg": 6,
            "xl": 3
          },
  // Choose a variant
  // See https://v4.mui.com/components/typography/#typography
          "variant": "h1/h2/h3/h4/h5/h6/subtitle1/subtitle2/body1/body2/caption/button",
          "color": "primary/secondary/#323425",
          "content": "This is a message with a hyperlink",
  // Optional link
          "link": "https://www.google.com",
          "linkColor": "inherit/primary/secondary/textPrimary/textSecondary",
          "underline": "none/hover/always",
          "style": {
            "textAlign": "right",
            "padding": "10px"
          }
        },
        {
          "type": "img",
          "gridSizes": {
            "xs": 12,
            "sm": 6,
            "md": 4,
            "lg": 6,
            "xl": 3
          },
  // Src of the image to display
          "src": "https://upload.wikimedia.org/wikipedia/commons/thumb/8/81/Wikimedia-logo.svg/1024px-Wikimedia-logo.svg.png",
  // Optional clickable link
          "link": "https://www.discord.com",
  // CSS Properties of the image
          "style": {
            "height": 50,
            "width": 50
          }
        },
        {
          "type": "divider",
          "gridSizes": {
            "xs": 12,
            "sm": 6,
            "md": 4,
            "lg": 6,
            "xl": 3
          },
  // Displays a lighter Divider on dark backdrops, probably essential
          "light": true,
  // You can probably leave this false but if it's giving you trouble, you may need to set to true
          "flexItem": false,
  // Displays the divider horizontally or vertically
          "orientation": "horizontal/vertical",
          "style": {
            "heigh": 10,
            "margin": 3
          }
        },
        {
          "type": "parent",
  // This is different from the others, this builds a parent Grid object
  // In the components array you can add an unlimited number of components (including additional parents)
  // These can be used to further split up the 12 row limit
          "gridSizes": {
            "xs": 12,
            "sm": 6,
            "md": 4,
            "lg": 6,
            "xl": 3
          },
          "spacing": 2,
          "style": {
            "margin": "10px 20px"
          },
          "alignItems": "center",
          "justifyContent": "flex-start",
          "components": [
  // Discord Login Button example
        {
          "type": "discord",
          "gridSizes": {
            "xs": 6
          },
          "link": "/auth/discord/callback",
          "text": "Login",
          "style": {}
        },
  // PayPal button example
        {
          "type": "button",
          "gridSizes": {
            "xs": 6
          },
          "link": "https://www.paypal.com",
          "content": "PayPal",
          "icon": "fab fa-paypal",
          "color": "secondary",
          "variant": "contained",
          "style": {
            "margin": 20
          }
        },
  // Telegram button example
        {
          "type": "telegram",
          "gridSizes": {
            "xs": 12
          },
          "telegramBotEnvRef": "TELEGRAM_BOT_NAME",
          "telegramAuthUrl": "/auth/telegram",
          "style": {
            "marginBottom": 20
          }
        },
          ]
        }
      ],
  // If you would like to add additional action buttons in the footer, next to the "close" button
      "footerButtons": [
        {
          "name": "Thing",
          "link": "https://www.google.com",
          "icon": "Help",
          "align": "center",
          "color": "primary",
          "donorOnly": false,
          "freeloaderOnly": false,
        }
      ]
    }

Custom Auth Strategies

See Auth Page