npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@mw-kit/mw-manager

v1.6.1

Published

Made with create-react-library

Downloads

103

Readme

Manager

Responsável por....

NPM JavaScript Style Guide

Instalando

yarn add @mw-kit/mw-manager

Usando

import React, { useEffect, useState, useCallback } from 'react'

import {
  MwManager,
  Toolbar,
  FiltersInterfaces,
  SortState,
  ColumnInterface,
  Dropdown,
  DropdownInterfaces,
} from 'mw-manager'

/**
 * Cabeçalho de exemplo
 */
const header: ColumnInterface[] = [
  {
    content: 'Nome',
    key: 'name',
    textAlign: 'left' as const,
    width: 4 as const,
    sortKey: 'name',
  },
  {
    content: 'Altura',
    key: 'height',
    textAlign: 'left' as const,
    width: 3 as const,
    sortKey: 'height',
    verticalAlign: 'end',
  },
  {
    content: 'Filmes',
    key: 'films',
    textAlign: 'center' as const,
    width: 3 as const,
    sortKey: 'films',
  },
  {
    content: 'Veiculos',
    key: 'vehicles',
    textAlign: 'center' as const,
    width: 3 as const,
    sortKey: 'vehicles',
  },
  {
    content: 'Naves',
    key: 'starships',
    textAlign: 'center' as const,
    width: 3 as const,
    sortKey: 'starships',
  },
]

interface DataInterface {
  name: string
  height: string
  mass: string
  hair_color: string
  skin_color: string
  eye_color: string
  birth_year: string
  gender: string
  homeworld: string
  films: string[]
  species: string[]
  vehicles: string[]
  starships: string[]
  created: string
  edited: string
  url: string
}

interface BodyInterface {
  nameStr: string
  name: JSX.Element
  height: string
  mass: string
  hair_color: string
  skin_color: string
  eye_color: string
  birth_year: string
  gender: string
  homeworld: string
  films: number
  species: number
  vehicles: number
  starships: number
  created: string
  edited: string
  url: string
}

const filters: FiltersInterfaces.Filter[] = [
  {
    label: 'Status',
    name: 'active',
    options: [
      { label: <b>Ativo</b>, value: 1 },
      { label: 'Inativo', value: 0 },
    ],
    delimiter: true,
  },
  {
    label: 'Personagem',
    name: 'people_id',
    options: async (value: string, page?: number) => {
      // inicializando a variavel que contera os parametros da query http
      let params: any = {}

      if (value.trim() !== '') params.search = value
      if (page) params.page = page

      // montando a http query string
      params = Object.keys(params)
        .map((key) => `${key}=${params[key]}`)
        .join('&')

      // concatenando a base url com a http query string e fazendo a requisicao
      const response = await fetch([baseURL, params].join('?'))
      // decodificando o conteudo json do body da requisicao
      const responseData: any = JSON.parse(await response.text())

      // retornando o conteudo do body da requisicao
      const options = responseData.results.map((e: any) => ({
        label: e.name,
        value: e.url.split('/').at(-2),
      }))

      return { options, lastPage: !responseData.next }
    },
    // disabled: true,
    allowEmptyString: true,
  },
]

const baseURL = 'https://swapi.dev/api/people/'

// essa funcao ira pegar os dados recebidos e fazer o parse para o formato que o manager precisa
const parseData = (data: DataInterface[]): BodyInterface[] => {
  return data.map((e) => {
    return {
      nameStr: e.name,
      name: <b>{e.name}</b>,
      height: e.height,
      mass: e.mass,
      hair_color: e.hair_color,
      skin_color: e.skin_color,
      eye_color: e.eye_color,
      birth_year: e.birth_year,
      gender: e.gender,
      homeworld: e.homeworld,
      films: e.films.length,
      species: e.species.length,
      vehicles: e.vehicles.length,
      starships: e.starships.length,
      created: e.created,
      edited: e.edited,
      url: e.url,
    }
  })
}

// essa funcao ira fazer a requisicao dos dados
const request = async (
  appliedFilters: FiltersInterfaces.AppliedFilter[],
  search: string,
  sort: SortState | null,
  page: number
): Promise<any> => {
  // inicializando a variavel que contera os parametros da query http
  let params: any = {
    page,
  }

  // se existir algo na busca, insere o valor nos parametros da requisicao
  if (search.length > 0) params.search = search

  // para cada filtro aplicado, adiciona o nome do filtro e o valor aos parametros da requisicao
  for (let i = 0; i < appliedFilters.length; i++) {
    const { name, value } = { ...appliedFilters[i] }
    params[name] = value
  }

  // se houver alguma ordenacao aplicada, adiciona o nome da ordenacao e a direcao aos parametros da requisicao
  if (sort) {
    params.sort = sort.sort
    params.direction = sort.direction
  }

  // montando a http query string
  params = Object.keys(params)
    .map((key) => `${key}=${params[key]}`)
    .join('&')

  // concatenando a base url com a http query string e fazendo a requisicao
  const response = await fetch([baseURL, params].join('?'))
  // decodificando o conteudo json do body da requisicao
  const responseData: any = JSON.parse(await response.text())

  // retornando o conteudo do body da requisicao
  return responseData
}

const App = () => {
  // estado controlador dos filtros aplicados
  const [appliedFilters, setAppliedFilters] = useState<
    FiltersInterfaces.AppliedFilter[]
  >([])

  // estado controlador do valor do input de pesquisa
  const [search, setSearch] = useState<string>('')
  // estado controlador dos dados recebidos
  const [data, setData] = useState<DataInterface[]>([])
  // estado controlador do conteudo do manager
  const [body, setBody] = useState<BodyInterface[]>([])
  // estado controlador da ordenacao
  const [sort, setSort] = useState<SortState | null>(null)
  // estado controlador do loading
  const [loading, setLoading] = useState<boolean>(false)
  // estado controlador da paginacao
  const [page, setPage] = useState<number>(1)
  // estado controlador do limite da paginacao
  const [isLastPage, setIsLastPage] = useState<boolean>(false)
  // estado controlador dos itens checados
  const [checkeds, setCheckeds] = useState<BodyInterface[]>([])
  // estado controlador do filtro de calendario
  const [date, setDate] = useState<Date>(new Date())

  // essa funcao tem os filtros aplicados, o valor do input de busca e o valor da ordenacao como dependencias
  const loadData = useCallback(async () => {
    setLoading(true)

    // fazendo requisicao dos dados
    const responseData = await request(appliedFilters, search, sort, page)
    // setando se a pagina atual e a ultima
    setIsLastPage(!responseData.next)
    // pegando os resultados da requisicao
    const results = responseData.results || []

    // se for a primeira pagina, seta os resultados, se nao, concatena os resultados
    setData(page === 1 ? results : (prev) => prev.concat(results))

    setLoading(false)
  }, [appliedFilters, search, sort, page])

  // essa funcao sera executada quando clicar no botao refresh da barra de ferramentas
  const reload = () => {
    page === 1 ? loadData() : setPage(1)
  }

  // sempre que alguma dependencia da funcao loadData for alterada, chama a funcao
  useEffect(() => {
    loadData()
  }, [loadData])

  // sempre que os dados sao alterados, faz o parse para o formato que o manager precisa
  useEffect(() => {
    setBody(parseData(data))
  }, [data])

  const getItemMenu = (item: BodyInterface): DropdownInterfaces.Item[] => {
    return [
      {
        content: 'Editar',
        onClick: () => {
          alert(`Editar ${item.nameStr}`)
        },
        rules: [],
      },
      {
        content: 'Excluir',
        onClick: () => {
          alert(`Excluir ${item.nameStr}`)
        },
        rules: [],
      },
    ]
  }

  const paginator = () => {
    if (!isLastPage) setPage((prev) => (prev += 1))
  }

  const getRowDisabled = (row: BodyInterface): boolean => {
    return (
      checkeds.length === 2 &&
      !checkeds.some((checked) => checked.nameStr === row.nameStr)
    )
  }

  return (
    <div style={{ padding: '14px', height: '100%' }}>
      <div
        style={{
          width: '100%',
          height: '100%',
          display: 'flex',
          flexDirection: 'column',
        }}
      >
        <Toolbar
          filters={{
            filters,
            setAppliedFilters,
            appliedFilters,
            bottomMargin: 14,
          }}
          search={{ setSearch }}
          loading={loading}
          reloader={reload}
          pagination={{ setPage, isLastPage, paginator }}
          calendar={{
            date,
            setDate,
          }}
          except={{}}
          before={<div>Elemento 4</div>}
          after={<div>Elemento 5</div>}
        >
          <div>Elemento 1</div>
          <div>Elemento 2</div>
          <div>Elemento 3</div>
          <Dropdown
            items={[
              {
                content: 'Ativar',
                onClick: () => alert('Ativar'),
                rules: [
                  {
                    rule: () => {
                      return checkeds.length > 0
                    },
                    message: (
                      <b style={{ color: 'red' }}>
                        Deve selecionar pelo menos um item
                      </b>
                    ),
                  },
                ],
              },
              {
                content: 'Inativar',
                onClick: () => alert('Inativar'),
                rules: [
                  {
                    rule: () => {
                      return checkeds.length > 0
                    },
                    message: 'Deve selecionar pelo menos um item',
                  },
                ],
              },
              {
                content: 'Deletar',
                onClick: () => alert('Deletar'),
                rules: [
                  {
                    rule: () => {
                      return checkeds.length > 0
                    },
                    message: 'Deve selecionar pelo menos um item',
                  },
                ],
              },
              {
                content: 'Extrair dados',
                onClick: () => alert('Extrair dados'),
                border: true,
                rules: [],
              },
            ]}
            loading={loading}
            axis='y'
          />

          <button style={{ padding: 0 }}>Botão 1</button>
          <button style={{ padding: 0 }}>Botão 2</button>
          <button style={{ padding: 0 }}>Botão 3</button>
        </Toolbar>

        <MwManager
          columns={header}
          rows={body}
          sort={{ sort, setSort }}
          hasFilters={appliedFilters.length > 0 || search.length > 0}
          messages={{
            empty: 'Nenhum personagem encontrado',
            emptyWithFilters:
              'Nenhum personagem encontrado para a busca realizada',
          }}
          loading={loading}
          paginator={paginator}
          page={page}
          setPage={setPage}
          checkeds={{ checkeds, setCheckeds, verticalAlign: 'start' }}
          getItemMenu={getItemMenu}
          itemMenuVerticalAlign='end'
          centerCoodinates={{ y: 50 }}
          getRowDisabled={getRowDisabled}
        />
      </div>
    </div>
  )
}

export default App

License

MIT © MundoWap