Executando verificação de segurança...
1

[PEDIDO DE AJUDA][NEXT JS] Como melhorar essa view.

Queria uma dica, sobre como poderia melhror essa view, sabe estou aprendendo sozinho, tenho um conhecimento legal com python já, mas só isso não é necessário, então comecei a realmente a aprender java, e tenho gostado bastante, mas estou vendo que tudo está ficando sempre bem grande e ainda quero colocar as funções ai que ainda nem coloquei, como editar,deletar, compartilhar, adicionar uma nova sessão, qual seria a dica de vocês.

O repositório está privado, mas se precisar eu abro pra mostrar como está ficando, queria dicas de como melhorar.

Aprendendo JS

import React, { useState } from "react";
import { FcDownload, FcPlus, FcSettings } from "react-icons/fc";
import { CiCircleChevUp, CiCircleChevDown } from "react-icons/ci";
import Link from "next/link";

function DashBoard() {
  const [openSessions, setOpenSessions] = useState([]);
  const [sessions, setSessions] = useState([
    {
      name: "Farmacologia",
      files: [
        {
          name: "Aula sobre medicamentos",
          type: "video",
        },
        {
          name: "Aula sobre absorção de medicamentos",
          type: "video",
        },
        {
          name: "Aula sobre os tipos de medicamentos",
          type: "video",
        },
        {
          name: "Aula sobre os tipos de medicamentos e suas ações no organismo",
          type: "video",
        },
      ],
    },
    {
      name: "Farmacognosia",
      files: [
        {
          name: "Aula sobre plantas medicinais",
          type: "video",
        },
        {
          name: "Aula sobre os tipos de extrações",
          type: "video",
        },
      ],
    },
  ]);

  return (
    <>
      <div className="mx-left container max-w-xl">
        <div className="h-max w-full  p-6 ">
          <h1 className="flex items-end  pb-3 text-2xl font-bold text-gray-700">
            <span className="flex-1">Minhas sessões</span>
            <span className="flex-3 text-end text-sm">2/10</span>

            <FcPlus
              onClick={() => {}}
              className="flex-2 ml-4 h-5 cursor-pointer hover:scale-110"
            />
          </h1>
          {sessions.map((session, index) => {
            const isOpen = openSessions.includes(index);

            return (
              <details
                key={index}
                className="my-2  rounded-lg  border-[0.0125rem] border-gray-400 border-opacity-30 px-4 py-4 text-sm shadow-md"
              >
                <summary
                  className="flex w-full flex-1 cursor-pointer select-none flex-row justify-between font-bold"
                  onClick={() => {
                    if (isOpen) {
                      setOpenSessions(
                        openSessions.filter((item) => item !== index),
                      );
                    } else {
                      setOpenSessions([...openSessions, index]);
                    }
                  }}
                >
                  <button>
                    {isOpen ? (
                      <CiCircleChevDown className="h-4 w-4" />
                    ) : (
                      <CiCircleChevUp className="h-4 w-4" />
                    )}
                  </button>
                  <p className="flex-1 px-5 text-start">{session.name}</p>
                  <p className="flex flex-1 flex-row items-center justify-end gap-2">
                    {session.files.length}/10
                  </p>
                  <details className="flex-3 relative ml-4 flex flex-row items-center justify-end gap-2">
                    <summary className="list-none">
                      <FcSettings />
                    </summary>
                    <div className="absolute right-0 top-[105%] z-10 flex w-40 flex-col items-start divide-y-[0.0125rem] rounded-lg border-[0.0125rem] bg-white shadow-md ">
                      <button className="w-full flex-1  px-4 py-2 text-start">
                        Editar
                      </button>
                      <button className="w-full flex-1  px-4 py-2 text-start">
                        Backup
                      </button>
                      <button className="w-full flex-1  px-4 py-2 text-start">
                        Compartilhar
                      </button>
                      <button className="w-full flex-1  px-4 py-2 text-start">
                        Excluir
                      </button>
                    </div>
                  </details>
                </summary>
                <div className="mt-2 flex flex-col divide-y-[0.0125rem] divide-gray-300 divide-opacity-30 ">
                  {session.files.map((file, index) => {
                    return (
                      <div
                        key={index}
                        className="my-1 flex flex-row items-center justify-center gap-2"
                      >
                        <div className="flex-1">{file.name}</div>
                        <Link
                          href="/dashboard"
                          className="flex-3 flex items-center justify-end"
                        >
                          <FcDownload />
                        </Link>
                      </div>
                    );
                  })}
                </div>
              </details>
            );
          })}
        </div>
      </div>
    </>
  );
}

export default DashBoard;


Carregando publicação patrocinada...
2

Olá amigo, o conceito fundamental do React é: Componentização. Você precisa pegar esse dashboard e literalmente dividi-lo em partes menores. Por exemplo, veja essa parte do seu código:

<button className="w-full flex-1 px-4 py-2 text-start">
    Editar
</button>
<button className="w-full flex-1 px-4 py-2 text-start">
    Backup
</button>
<button className="w-full flex-1 px-4 py-2 text-start">
    Compartilhar
</button>
<button className="w-full flex-1 px-4 py-2 text-start">
    Excluir
</button>

Percebe que eles são iguais? Portanto, crie um componente separado para eles e apenas o importe em seu dashboard.

Além disso, observe este trecho de código:

<summary
    className="flex w-full flex-1 cursor-pointer select-none flex-row justify-between font-bold"
    onClick={() => {
        if (isOpen) {
            setOpenSessions(
                openSessions.filter((item) => item !== index),
            );
        } else {
            setOpenSessions([...openSessions, index]);
        }
    }}
>

A lógica do código não deve estar dentro do JSX. Crie uma função antes do return do JSX e use essa função no evento OnClick. Ademais, lembre-se sempre de manter seus componentes o mais limpos possível. Boa sorte, amigo. Você consegue.

2
2

as sessions ficarão estáticas no frontend? Se Sim, não precisa ser um estado e sim pode ser um arquivo de data separado.

Algo como data.js

export const sessions = [
    {
      name: "Farmacologia",
      files: [
        {
          name: "Aula sobre medicamentos",
          type: "video",
        },
        {
          name: "Aula sobre absorção de medicamentos",
          type: "video",
        },
        {
          name: "Aula sobre os tipos de medicamentos",
          type: "video",
        },
        {
          name: "Aula sobre os tipos de medicamentos e suas ações no organismo",
          type: "video",
        },
      ],
    },
    {
      name: "Farmacognosia",
      files: [
        {
          name: "Aula sobre plantas medicinais",
          type: "video",
        },
        {
          name: "Aula sobre os tipos de extrações",
          type: "video",
        },
      ],
    },
  ];

Vejo também que a maioria dos buttons se repetem. Logo pode ter um componente no próprio arquivo para não repetir o mesmo código css.

const CustomButton = ({text}) => (
    <button className="w-full flex-1  px-4 py-2 text-start">{text}</button>
)

Tenho a prática de não deixar funções diretas no onClick, geralmente eu separo.

function toggleSummary ({isOpen, index}) {
    if(!isOpen) {
        setOpenSessions([...openSessions, index]);
        return;
    }
    setOpenSessions(openSessions.filter((item) => item !== index));
}

Não é muita coisa, mas já ajuda um pouco. O tailwind tem como "contra" a verbosidade, mas seu arquivo ainda está bem pequeno.

O resultado final seria.

import React, { useState } from "react";
import { FcDownload, FcPlus, FcSettings } from "react-icons/fc";
import { CiCircleChevUp, CiCircleChevDown } from "react-icons/ci";
import Link from "next/link";
import { sessions } from "./data";

function CustomButton({ text }) {
  return (
    <button className="w-full flex-1  px-4 py-2 text-start">{text}</button>
  );
}

export default function DashBoard() {
  const [openSessions, setOpenSessions] = useState([]);

  function toggleSummary({ isOpen, index }) {
    if (!isOpen) {
      setOpenSessions([...openSessions, index]);
      return;
    }
    setOpenSessions(openSessions.filter((item) => item !== index));
  }

  return (
    <div className="mx-left container max-w-xl">
      <div className="h-max w-full  p-6 ">
        <h1 className="flex items-end  pb-3 text-2xl font-bold text-gray-700">
          <span className="flex-1">Minhas sessões</span>
          <span className="flex-3 text-end text-sm">2/10</span>
          <FcPlus className="flex-2 ml-4 h-5 cursor-pointer hover:scale-110" />
        </h1>

        {sessions.map((session, index) => {
          const isOpen = openSessions.includes(index);

          return (
            <details
              key={index}
              className="my-2  rounded-lg  border-[0.0125rem] border-gray-400 border-opacity-30 px-4 py-4 text-sm shadow-md"
            >
              <summary
                className="flex w-full flex-1 cursor-pointer select-none flex-row justify-between font-bold"
                onClick={() => toggleSummary({ isOpen, index })}
              >
                <button>
                  {isOpen ? (
                    <CiCircleChevDown className="h-4 w-4" />
                  ) : (
                    <CiCircleChevUp className="h-4 w-4" />
                  )}
                </button>
                <p className="flex-1 px-5 text-start">{session.name}</p>
                <p className="flex flex-1 flex-row items-center justify-end gap-2">
                  {session.files.length}/10
                </p>
                <details className="flex-3 relative ml-4 flex flex-row items-center justify-end gap-2">
                  <summary className="list-none">
                    <FcSettings />
                  </summary>
                  <div className="absolute right-0 top-[105%] z-10 flex w-40 flex-col items-start divide-y-[0.0125rem] rounded-lg border-[0.0125rem] bg-white shadow-md ">
                    <CustomButton text="Editar" />
                    <CustomButton text="Backup" />
                    <CustomButton text="Compartilhar" />
                    <CustomButton text="Excluir" />
                  </div>
                </details>
              </summary>
              <div className="mt-2 flex flex-col divide-y-[0.0125rem] divide-gray-300 divide-opacity-30 ">
                {session.files.map((file, index) => {
                  return (
                    <div
                      key={index}
                      className="my-1 flex flex-row items-center justify-center gap-2"
                    >
                      <div className="flex-1">{file.name}</div>
                      <Link
                        href="/dashboard"
                        className="flex-3 flex items-center justify-end"
                      >
                        <FcDownload />
                      </Link>
                    </div>
                  );
                })}
              </div>
            </details>
          );
        })}
      </div>
    </div>
  );
}

Obs.: Se a identação estiver toda errada, perdoe-me. Não tinha onde arrumar no momento.

1

Muito obrigado pela ajuda, achei super interessante, ficou otimo, entendi tudo que você quis dizer, e queria saber se não estava tão ruim também né, mas que bom que não ficou tão diferente do que eu achava, e os valores vão vir do backend, vou usar django como backend ,mas por enquanto estou mockando esses valores para testar apenas.

Mas entendi, outra questão é a seguinte, onde eu vou adicionar uma nova seção, corrigindo pois coloquei errado, o sessão tem um sentido diferente de seção, estranho né, mas beleza ja troquei.

Para eu criar uma nova sessão seria interessante eu criar como se vosse um MCV?
Tenho a view, que é esse, ela vai ter o controller que no caso seria a função createNewSession e o model viria no caso do django. E como ficaria a distribuição desseas pastas
Não sei se consegui ser claro, mas resumindo tenho os botão para criar nova seção, para editar as seções existentes, onde eu devo criar essas funções.

.
├── next
├── pages/
│   ├── cadastras
│   ├── dashboard/
│   │   ├── configuracao
│   │   └── conta
│   ├── entrar
│   ├── interface/
│   │   ├── components/
│   │   │   └── .... components
│   │   └── recuperar
│   ├── __app.js
│   └── index.js
├── public/
│   ├── layout
│   └── svgs  
├── styles/
│   └── globals.css
└── tests
1

Geralmente eu coloco toda interação com endpoints externos dentro de uma pasta chamada services/data/sessions

Pode ser uma função genérica que recebe o metodo, rota e options. Recomendo utilizar o axios, pois o mesmo trás diversas facilidades

1

Amigo, sou back-end então não vou conseguir ajudar no código.
Mas por favor, alinha o 2/10 com o icone de configurações, dá um pouco de agonia sabe?

-3