Let people know about fetch problems with a little toast

store.js
1
2
3
4
5
6
7
8
9
10
11
import { writable } from 'svelte/store'

// message types are: info, warning, error, success
const toastData = {
message: "",
messageType: "success",
loadDelay: 1000,
dismissDelay: 5000
}

export let toastMessage = writable(toastData)
Toast.svelte
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<script>
import { toastMessage } from '../store.js'
import { fly } from 'svelte/transition'

let show = false
let msg = ""

toastMessage.subscribe(value => {
if (msg !== $toastMessage.message) {
if (value.loadDelay > 0) {
setTimeout(() => {
show = true
if (value.dismissDelay > 0) setTimeout(() => { show = false }, value.dismissDelay)
}, value.loadDelay)
} else {
show = true
if (value.dismissDelay > 0) setTimeout(() => { show = false }, value.dismissDelay)
}
msg = $toastMessage.message
}
})

function handleClick() {
show = false
}

function getColor(msgType) {
if (msgType === "warning") { return "orange" }
if (msgType === "error") { return "red" }
if (msgType === "info") { return "blue" }
if (msgType === "success") { return "green" }
return "gray"
}


</script>

<style>
.toastMessage {
width: 400px;
max-width: 90%;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
}
</style>

{#if show}

<div
class="toastMessage fixed z-50 cursor-pointer flex items-center bg-{getColor($toastMessage.messageType)}-600 border-l-4 border-{getColor($toastMessage.messageType)}-800 py-2 px-3 shadow-md mb-2 "
on:click|once={handleClick}
in:fly="{{ y: 200, duration: 1000 }}"
out:fly="{{ y: 200, duration: 2000 }}"
>
<!-- icon -->
<div class="text-{getColor($toastMessage.messageType)}-600 rounded-full bg-white mr-3">
<svg width="1.8em" height="1.8em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
{#if $toastMessage.messageType === "warning"}
<path d="M7.002 11a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 4.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 4.995z"/>
{/if}
{#if $toastMessage.messageType === "success"}
<path fill-rule="evenodd" d="M10.97 4.97a.75.75 0 0 1 1.071 1.05l-3.992 4.99a.75.75 0 0 1-1.08.02L4.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093 3.473-4.425a.236.236 0 0 1 .02-.022z"/>
{/if}
{#if $toastMessage.messageType === "info"}
<path d="M8.93 6.588l-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588z"/>
<circle cx="8" cy="4.5" r="1"/>
{/if}
{#if $toastMessage.messageType === "error"}
<path fill-rule="evenodd" d="M11.854 4.146a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708-.708l7-7a.5.5 0 0 1 .708 0z"/>
<path fill-rule="evenodd" d="M4.146 4.146a.5.5 0 0 0 0 .708l7 7a.5.5 0 0 0 .708-.708l-7-7a.5.5 0 0 0-.708 0z"/>
{/if}
</svg>
</div>
<!-- message -->
<div class="text-white">
{@html $toastMessage.message }
</div>
</div>

{/if}
toastMaker.js
1
2
3
4
5
6
7
8
9
10
import { toastMessage } from '../store.js'

export default function (messageType = "info", message = "We're experiencing technical difficulties. Please try again later.", loadDelay = 0, dissmissDelay = 5000) {
toastMessage.set({
message: message,
messageType: messageType,
loadDelay: loadDelay,
dismissDelay: dissmissDelay
})
}
cheers.js
1
2
3
4
5
6
7
8
9
10
import toastMaker from '../js/toastMaker'

fetch('http://thatwontwork.org/ug/mybrains')
.then(response => response.json())
.then(data => {
// you're never really getting here
})
.catch(ex => {
toastMaker( "error", "We're having a problem loading this data. Please try back later.")
})