Skip to content

Commit

Permalink
feat: implement snackbar component (#6)
Browse files Browse the repository at this point in the history
* feat: implement Snackbar component

Implement the Snackbar component to handle snackbar creation and removal
based on the provided configuration. The Snackbar class consists of a
constructor method that initializes the configuration, a create method
to create snackbars, and a remove method to remove snackbars. This
implementation ensures that the provided configuration is verified
before creating or removing snackbars.

* refactor: replace create method with render method

Replaced the `createSnackbar` method with the `renderSnackbar` method in
the Snackbar class to streamline the process of rendering. Directly
rendering the Snackbar makes more sense and reduces complexity when
using the Snackbar class.

* refactor: remove unnecessary parameter

Removed an unnecessary parameter from the `removeSnackbar` method to
streamline its implementation and improve clarity.

* refactor: merge render and remove methods

Merged the render and remove methods in the Snackbar class to simplify
its interface and enhance clarity. The unnecessary parameter has been
removed, resulting in a more streamlined and user-friendly implementation.

* feat: add render then remove snackbar function

This feature introduces a new function for rendering a snackbar message
and then automatically removing it after a certain duration. The
function combines the rendering and removal processes into a single
action, enhancing usability and reducing complexity.

* refactor: update import paths for module resolution

Updated import paths in component files to use module resolution aliases
defined in jsconfig.json. This change improves code readability and
maintainability by replacing relative paths with aliases.

* test: merge test files into one

Combine multiple test files into a single test file to reduceunnecessary module tests. This change simplifies navigation and improvescodebase organization.

* test: ensure rendering and removal works properly

Add tests to verify that the Snackbar component correctly renders and
removes messages with valid configurations.
  • Loading branch information
chessurisme committed Jun 17, 2024
1 parent da36b71 commit 288951f
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
41 changes: 41 additions & 0 deletions src/components/__tests__/snackbar.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict'

import { JSDOM } from 'jsdom'
import { Snackbar } from '@components/snackbar'

const dom = new JSDOM('<!DOCTYPE html>')
global.window = dom.window
global.document = window.document
global.HTMLElement = window.HTMLElement
global.requestAnimationFrame = (callback) => {
setTimeout(callback, 1000 / 60)
}

describe('Snackbar', () => {
beforeEach(() => {
document.body.innerHTML = null
})

describe('renderThenRemove', () => {
it('should create a Snackbar instance with valid config', () => {
const config = { message: 'The quiz pack is successfully imported!' }

const snackbar = new Snackbar(config)

expect(snackbar).toBeInstanceOf(Snackbar)
expect(snackbar.renderThenRemove).toBeInstanceOf(Function)
})

it('should render and remove snackbar with valid config', () => {
const config = { message: 'The quiz pack is successfully imported!' }

const snackbar = new Snackbar(config)
snackbar.renderThenRemove()

expect(document.body).not.toBeNull()
expect(document.body.querySelector('#snackbar').textContent).toBe(
'The quiz pack is successfully imported!'
)
})
})
})
83 changes: 83 additions & 0 deletions src/components/snackbar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
'use strict'

import { isConfigVerified } from '@utilities/config/config-verifier'
import { setAttributes } from '@utilities/components/set-attributes'

class Snackbar {
static #snackbar_queue = []
static #is_displaying = false

#config

constructor(config) {
this.#config = isConfigVerified('snackbar', config) ? config : {}
}

renderThenRemove() {
const { message } = this.#config
Snackbar.#enqueue(message)
}

static #enqueue(message) {
Snackbar.#snackbar_queue.push(message)
Snackbar.#processQueue()
}

static #processQueue() {
if (Snackbar.#is_displaying || Snackbar.#snackbar_queue.length === 0) {
return
}

Snackbar.#is_displaying = true
const message = Snackbar.#snackbar_queue.shift()
Snackbar.#display(message)
}

static #display(message) {
const existing_snackbar = document.getElementById('snackbar')
if (existing_snackbar) {
existing_snackbar.remove()
}

const SNACKBAR = Snackbar.#create(message)
document.body.appendChild(SNACKBAR)

Snackbar.#remove(SNACKBAR)
}

static #create(message) {
const SNACKBAR = document.createElement('div')
setAttributes(SNACKBAR, {
class: 'snackbar',
id: 'snackbar'
})
SNACKBAR.textContent = message

return SNACKBAR
}

static #remove(SNACKBAR) {
let start
const duration = 3000

function animate(timestamp) {
if (!start) start = timestamp

const progress = timestamp - start

if (progress > duration) {
SNACKBAR.remove()
SNACKBAR = null
Snackbar.#is_displaying = false
Snackbar.#processQueue()
return
}

requestAnimationFrame(animate)
}

requestAnimationFrame(animate)
}
}

export { Snackbar }

0 comments on commit 288951f

Please sign in to comment.