This is how I configure matomo on my server, using docker containers and nginx.
export MARIADB_USER=
export MARIADB_PASSWORD=
export PORT=| import { Storage, StorageApi, storedString, storedValue } from './storage' | |
| class MockStorageApi implements StorageApi { | |
| public items = new Map<string, string>() | |
| getItem(key: string): string | null { | |
| return this.items.get(key) ?? null | |
| } | |
| setItem(key: string, value: string): void { |
| import { act, renderHook } from '@testing-library/react' | |
| import { useWaitFor } from './use-wait-for' | |
| describe('useWaitFor', () => { | |
| beforeEach(() => { | |
| jest.useFakeTimers() | |
| }) | |
| it('calls then when the condition is true', () => { |
| class StubStorage implements Storage { | |
| readonly items = new Map<string, string>(); | |
| get itemsArray() { | |
| return Object.values(this.items); | |
| } | |
| get length(): number { | |
| return this.itemsArray.length; | |
| } |
| const randomInteger = (max: number) => { | |
| return Math.floor(Math.random() * max); | |
| }; | |
| const secretSanta = (people: string[]): Array<[string, string]> => { | |
| const result: Array<[string, string]> = []; | |
| const available = people.slice(1); | |
| let person1 = people[0]; | |
| while (available.length > 0) { |
| import { renderHook } from '@testing-library/react'; | |
| import { createMemoryHistory } from 'history'; | |
| import { Router } from 'react-router-dom'; | |
| import { useSearchParams } from './use-search-params'; | |
| describe('useSearchParams', () => { | |
| const render = (history = createMemoryHistory()) => { | |
| return renderHook(useSearchParams, { | |
| wrapper: ({ children }) => ( |
| import { ReactNode, useCallback, useEffect, useReducer, useState } from 'react'; | |
| type SetFieldError = (field: string, message: ReactNode) => void; | |
| export type FieldErrorsHandler<T> = (data: T, setError: SetFieldError) => void; | |
| type SetFormError = (message: ReactNode) => void; | |
| export type FormErrorHandler<T> = (data: T, setError: SetFormError) => void; | |
| type ClearFieldError = (field: string) => void; | |
| type ClearAllFieldErrors = () => void; |
| // !! This is not a production-ready snippet !! | |
| // It's just some lines of code I put together to try using SWR with an abstraction layer for the data source | |
| // | |
| // In this example, I use a fake provider (InMemoryTodosProvider) that could be useful for integration testing, | |
| // in storybook, or while the backend is not yet ready. It is then "injected" using a react context. | |
| // The typings isn't quite right, but I don't have much time to do better. Feel free to use this code if you want to. | |
| import { DataProvidersContext, DataProviders } from './data-providers'; | |
| import { InMemoryTodoProvider } from './todo.provider'; | |
| import { Todos } from './todos'; |
| #!/usr/bin/env node | |
| const crypto = require("crypto"); | |
| const fs = require("fs"); | |
| const replaceIds = (obj) => { | |
| if (typeof obj !== "object" || obj === null) { | |
| return obj; | |
| } |
| import { ForwardedRef, useCallback } from 'react'; | |
| const useMergeRefs = <T extends HTMLElement>(...refs: Array<ForwardedRef<T>>): ForwardedRef<T> => { | |
| return useCallback((element: T | null) => { | |
| for (const ref of refs) { | |
| if (typeof ref === 'function') { | |
| ref(element); | |
| } else if (ref) { | |
| ref.current = element; | |
| } |