Mellonn's new website

Photo Credit: Joakim Rosenfeldt

Joakim Rosenfeldt Pedersen

Updated August 12, 2022

Making another website

Been some time again, haven't it? Well yeah, it's been over a month now, and a lot have happened since then! I really hope you guys have been enjoying life during the summer, I definitely have. I must also confess that I've been looking much forward to writing this exact blog post, because I have so much stuff to share with you guys! Why don't we just get started then?

These last weeks' (or more) progress

Let me just start by addressing the elephant in the room, a new website?? Exactly! I didn't like the old one, and the old ones' subscription was about to run out, and it was quite expensive for the feature (or lack thereof). Another bigger thing is the use of a new payment system, still by Stripe though. This switch comes with some great features, but also some drawbacks, I'll get deeper into this later.. I've also added some onboarding pages to the web-app (like the ones in the mobile app). I've of course also made some other smaller changes, that I will be going over too, You should know the drill by now.

The elephant (website)

Let's be honest, the old website wasn't exactly beautiful, nor was it inviting, but it got the job done. Until now. Say hello to the new website, which should (hopefully) make my life a bit easier! The new website have pretty much the same features as the old one, BUT I now have full control over the site. Having made it in Angular, just like the web-app, I'm very excited to show it off.

Front page/landing page

I won't be showing any screenshots her, cause I think it's easier if go see the page yourself 😉. But the story about the front page is a longer one, or at least it feels like a shorter one...

Thoughts behind it: As every other front page, its' job is to tell the visitor about what's the website is all about, all this while keeping the visitor engaged and interested. That last part is definitely the hardest part, it means having a nice design, not too much going on but enough to keep the user interest. It's a fine line to say the least.

Inspiration: It's always extremely important to get some inspiration from somewhere else, and find what others do right and wrong. Here's a list of pages I looked at during my exploring and scouring of the internet, and some notes about them:

  • MacBook Air with M2 chip - Apple
    • Apple, as we all know, is some absolute geniuses when it comes to marketing, and their website showing the new Macbook Air is no exception. With animations keeping the visitor engaged all throughout the selling points and specs.
  • Timeslot
    • This is a beautifully designed website, showcasing a mobile app and doing it all while (again) keeping the visitor enganged.
  • The Bewegen Bike Share System - Power Your Ride
    • An odd website trying a way of designing/animating websites I haven't seen before, I just included it because I think it's a fun experience. It must be said that having that feeling after visiting a website is so special and should be the goal of every web designer.
  • Sleepiest
    • This is definitely my favourite of the bunch. It's simple, beautiful, extremely informative and I could simply spend hours watching every nook and cranny of this website. I really recommend you take a good look and explore this page, also take a look at the statistics page!
  • Obsidian
    • Very simple and informative page, not much to talk about, it's just good. Obsidian I use myself as my goto note taking software, and the help page of Mellonn Speak (I'll get to that).

Now with all that inspiration, you'll probably see that I haven't used any animations on the front page myself... Well I plan on doing it, but after about a week of working on it, I found that it takes a long time to learn, and most of all... Do well. This front page is simply not something I had the time to spend weeks polishing it to the level that Apple or Sleepiest has. So I ended up taking a lot of inspiration from Obsidian, because it's simple and informative, all I need for now!

Blog page

I knew I would need to make a new blog page, because it's a big part of my process, to document everything. But as I'm making more and more progress, and as a part of that also writing more blog posts, the old one got harder to find the post you wanted to read. This means that I have now created a category system going with the new blog page. You can now use the categories to search for the exact type of blog post you want to read. I'm also planning to add a search bar in the future.

Some parts of the new blog page still isn't quite done, as an example is the preview when adding a link to a social platform (like LinkedIn). When using an SPA as with Angular, I've found it isn't too easy with the way I've done the blog posts...

Speaking of the way I've done the blog posts. I've made my life much easier with the new website! With everything now being displayed with the Markdown format (a universal file format to display all kinds of text). Why markdown? Because Obsidian uses markdown, which means all my blog posts are written with the markdown format, before being published. Converting it to something Squarespace understood, left me with about 30 minutes of work publishing every blog post. And even better, I can now easier share code snippets with you guys! Let's just try an example, because I'm excited to try it out:

How the "Blog viewer page is built"

Firstly when someone opens a blog post, it will get the database ID from the url of the page as an example the last blog post has the url: https://www.mellonn.com/blog/6a0552c7-d510-4094-96a5-378ce0743030, this means that the database ID it has to get is "6a0552c7-d510-4094-96a5-378ce0743030". When it have gotten the database element with the corresponding ID, it has all the information it needs to displaying the blog post. But when the visitor opens a blog post directly for the first time, Amplify first have to be initiated, so it will try until it gets something to display. Let's take a look at the Typescript first, where all this stuff happens:

import { AfterViewInit, Component, OnInit } from '@angular/core';
import { Meta } from '@angular/platform-browser';
import { ActivatedRoute, Router } from '@angular/router';
import { DataStore } from '@aws-amplify/datastore';
import { Post } from 'src/models';

  

@Component({
	selector: 'app-blog-viewer',
	templateUrl: './blog-viewer.component.html',
	styleUrls: ['./blog-viewer.component.scss']
})

export class BlogViewerComponent implements OnInit, AfterViewInit {
	id: string = '';
	post: Post | undefined;
	markdown: string = '';
	isLoading: boolean = true;
	
	  
	
	constructor(
		private route: ActivatedRoute,
		private router: Router,
		private meta: Meta,
	) { }
	
	  
	
	async ngOnInit() {
		this.id = this.route.snapshot.paramMap.get('id') ?? '';
		this.markdown = await this.getPost(this.id);
		this.isLoading = false;
	}
	
	  
	
	async ngAfterViewInit() {
		while (!this.isLoading) {
			if (this.markdown == 'error') {
				this.markdown = await this.getPost(this.id);
				break;
			}
			console.log('no error');
			break;
		}
	}
	
	  
	
	async getPost(id: string): Promise<string> {
		let isTrying = true;
		let tries = 0;
		
		while (isTrying) {
			try {
				this.post = await DataStore.query(Post, id)!;
				if (this.post?.markdownKey == undefined) throw 'notOkay';
				
				const response = await fetch(this.post?.markdownKey!);
				if (!response.ok) throw 'notOkay';
				
				return await response.text();
			} catch (err) {
				if (err == 'notOkay') {
					isTrying = true;
					tries++;
					if (tries == 50) return 'error';
				} else {
					console.error('error getting post', err);
					return 'error';
				}
			}
			
			await new Promise(resolve => setTimeout(resolve, 100));
		}
		return 'error';
	}
}

Now we can take a look at the HTML displaying all of this:

<div class="content">
	<div class="top">
		<img src="{{post?.pictureKey}}" alt="{{post?.title}}">
		<p>{{post?.author}}</p>
		<p class="date">Updated on {{post?.date | date:'MMMM d, y'}}</p>
	</div>
	<div class="markdown">
		<markdown [data]="markdown"></markdown>
	</div>
</div>

And at last the CSS (SCSS in my case):

.content {
	max-width: 700px;
	margin: 0 2px;
	position: relative;
	left: 50%;
	transform: translate(-50%);
	padding: 10px;
	
	.top {
		margin-top: 50px;
		
		img {
			border-radius: 15px;
		}
		
		p {
			margin: 15px 0 0 15px;
			font-size: 0.9em;
			font-weight: bold;
		}
		
		.date {
			color: #505050c1;
			font-weight: normal;
			margin-top: 5px;
		}
	}	
	
	.markdown {
		margin: 50px 0 100px 0;
		width: 100%;
		
		markdown {
			width: 100%;
		}
	}
}

Now I hope this works well...

Help page/Documentation

At first I would try and create a help page myself, where users can search for help and find it as quickly as possible. But while doing this, I found that this was just too big a task for me to do now. But this means I'm (again) using Obsidian, they can host a site with all your notes for you. On this site visitors can search everything easily, and I can link to every thing easily. While doing all this, It is also extremely easy for me to update the notes, with it being synced to my notes on my local computer.

In the future I will also be publishing my documentation on this page. For now you can see all my code on Github, I've just made all the code public on there 😉.

Updates to Mellonn Speak Web

As if making a whole new website wasn't enough for one blog post... Well, it wasn't! Over the last couple of weeks, my biggest assignment has been to, migrating the web-app to using the Stripe Orders system, instead of using the classic Payment intents.

Stripe Orders

Why's that? You might ask. That's because of a thing we have in pretty much every single country on this earth. Taxes. Let me just say, they're not easy to do in ONE country, and when pretty every country do them differently, I'm giving up. But what does that have to do with Stripe Orders? Stripe Orders is a new system, new as in still in Beta, from Stripe, where every time someone needs to pay for something, you make an order. This order will then consist of the products they're purchasing and what currency. Now to the smart part of this. When someone then pay for something, Stripe will then automatically calculate the taxes associated with the payment! This is based on the location of the customer, which is being processed with the order.

Now with the location, that was a pretty tricky thing to figure out because of two reasons:

  1. I didn't want to ask the customer for information about their whereabouts. This would add one extra step to the process of purchasing.
  2. I don't want to use geolocation, it's too accurate and I feel like it goes against some of my own privacy principles. Then how did I go about doing it? IP-addresses. You can do a lot with IP-addresses probably more than you know... But the important thing is, I can get the country in which the user is. I can then feed the country to Stripe, and they will then calculate the taxes for me, and I have less work to do! As mentioned earlier, there are pretty no two countries which do taxes the same, and the United States and Canada are no different here. In those two countries taxes are different across each of the states... This means that Stripe requires you to submit the country, state and postal code for those countries. So if you live in USA or Canada, you unfortunately have one extra step, but I guess you're used to it.

Another thing that has changed because of this migration, is the way you have to pay. I now use the Payment Element, instead of the Card Element. This for now means that you unfortunately can't use saved credit cards when paying. But I'm doing what I can to get this feature back, because I want to make the purchasing process as easy and quick as possible.

Other updates and bug fixes

Apart from migrating to Stripe Orders, there's not much I've done to the web-app. So I'll try and list some of the updates and bug fixes I've done, those I remember at least...

  • Updates to the promotion system. It wasn't working quite well enough, so I've ironed out a few minor things.
  • Responsiveness of the page have gotten much better. Overall usability on much is pretty good, although not as good as the native app for mobile, but usable. It still needs some tweaking to be good enough, but it's getting there.
  • Drop down menus are now clickable, instead of only activating when hovering over them. This I realised was essential, if the site should be at least usable on mobile and tablets.
  • Updated font sizes. Made everything a bit smaller, but I will in the not so distant future be looking at a small refresh of the pages design, it's too orange i my opinion. I will be looking at changing the pallet of Mellonns' whole ecosystem.

What's next?

I'm beginning to reach out to student associations throughout Denmark, and I'll see where it takes Mellonn. Besides from contacting and reaching out to associations, I will begin work on redesigning the mobile app. This redesign will probably be leading the redesign changes coming to the Mellonn ecosystem. This time though, I will do my best to do it right, but we'll see how long it takes, I'm definitely going to need a lot of feedback going forward.

See you again at some point!

I actually like doing these once a month(-ish) blog posts, they're nice even though it takes some extra time to write a single post, it feels like it takes up less time overall. But I'll be starting at the university in a few weeks, so I wouldn't expect the longest posts from now on though, maybe a little check-in here and there, but probably no novel sized posts like this one.