diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..35843139 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +node_modules +__tests__ +.github +.jest +.storybook +.npmrc \ No newline at end of file diff --git a/.env b/.env new file mode 100644 index 00000000..850bbda3 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +VITE_UNIVERSIME_API=http://localhost:8080/api +VITE_BUILD_HASH=development diff --git a/.env.docker b/.env.docker new file mode 100644 index 00000000..7776362f --- /dev/null +++ b/.env.docker @@ -0,0 +1,2 @@ +VITE_UMAMI_URL=@UMAMI_URL@ +VITE_UMAMI_ID=@UMAMI_ID@ \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..526c8a38 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.sh text eol=lf \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..33540841 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,13 @@ +# These are supported funding model platforms + +github: [universi-me]# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/workflows/build-check.yml b/.github/workflows/build-check.yml new file mode 100644 index 00000000..5aac02aa --- /dev/null +++ b/.github/workflows/build-check.yml @@ -0,0 +1,42 @@ +name: Build Check + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: '15' + + - name: Install dependencies + run: npm install --include=dev + + - name: Install dependencies + run: npm i --save-dev @types/jest + + + - name: Set NODE_ENV to production + run: echo "NODE_ENV=production" >> $GITHUB_ENV + + - name: Build + run: npm run build + + - name: Check for build success + run: | + if [ $? -ne 0 ]; then + echo "Error: 'npm run build' failed" + exit 1 + fi diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml new file mode 100644 index 00000000..9db32d28 --- /dev/null +++ b/.github/workflows/build-docker-image.yml @@ -0,0 +1,65 @@ +name: Build, Test, and Push Docker Image + +on: + release: + types: [published] + +jobs: + build-test-and-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Cache Docker layers + uses: actions/cache@v2 + with: + path: ~/.docker + key: ${{ runner.os }}-docker-${{ hashFiles('**/Dockerfile') }} + restore-keys: | + ${{ runner.os }}-docker- + + - name: Cache npm dependencies + uses: actions/cache@v2 + with: + path: ~/.npm + key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-npm- + + - name: Install dependencies + run: rm -rf node_modules && npm ci + + - name: Set environment variable + id: set-env + run: echo "VITE_UNIVERSIME_API=/api" >> $GITHUB_ENV + + - name: Set VITE_BUILD_HASH environment variable + id: set-build-hash + run: echo "VITE_BUILD_HASH=${{ github.event.release.tag_name }}" >> $GITHUB_ENV + + - name: Run Build + run: npm run build + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Docker image + run: | + docker buildx create --use + echo "${{ github.event.release.tag_name }}" > ./build.hash + docker buildx build \ + --platform linux/arm64,linux/amd64 \ + --build-arg VITE_BUILD_HASH=${{ github.event.release.tag_name }} \ + -t ghcr.io/${{ github.repository_owner }}/${{ github.repository_name || github.event.repository.name }}:${{ github.event.release.tag_name }} \ + -t ghcr.io/${{ github.repository_owner }}/${{ github.repository_name || github.event.repository.name }}:latest \ + --push \ + . \ No newline at end of file diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml new file mode 100644 index 00000000..8ee93cf9 --- /dev/null +++ b/.github/workflows/codecov.yml @@ -0,0 +1,38 @@ +name: Running Code Coverage + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [14.x] + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + fetch-depth: 2 + + - name: Set up Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + + - name: Install dependencies + run: npm install + + - name: Run tests + run: npm run test + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 00000000..61f7e7cc --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,23 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement +name: 'Dependency Review' +on: + pull_request: + branches: + - main + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@v3 + - name: 'Dependency Review' + uses: actions/dependency-review-action@v2 diff --git a/.gitignore b/.gitignore index a547bf36..a836ca71 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ node_modules dist dist-ssr *.local +.jest/coverage/* # Editor directories and files .vscode/* diff --git a/.jest/__mocks__/fileMock.js b/.jest/__mocks__/fileMock.js new file mode 100644 index 00000000..86059f36 --- /dev/null +++ b/.jest/__mocks__/fileMock.js @@ -0,0 +1 @@ +module.exports = 'test-file-stub'; diff --git a/.jest/setup-tests.js b/.jest/setup-tests.js new file mode 100644 index 00000000..331666ce --- /dev/null +++ b/.jest/setup-tests.js @@ -0,0 +1 @@ +import '@testing-library/jest-dom'; \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..e9ee3cb4 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +legacy-peer-deps=true \ No newline at end of file diff --git a/.storybook/main.ts b/.storybook/main.ts new file mode 100644 index 00000000..9a210127 --- /dev/null +++ b/.storybook/main.ts @@ -0,0 +1,17 @@ +import type { StorybookConfig } from "@storybook/react-vite"; +const config: StorybookConfig = { + stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"], + addons: [ + "@storybook/addon-links", + "@storybook/addon-essentials", + "@storybook/addon-interactions", + ], + framework: { + name: "@storybook/react-vite", + options: {}, + }, + docs: { + autodocs: "tag", + }, +}; +export default config; diff --git a/.storybook/preview.ts b/.storybook/preview.ts new file mode 100644 index 00000000..1c372b69 --- /dev/null +++ b/.storybook/preview.ts @@ -0,0 +1,15 @@ +import type { Preview } from "@storybook/react"; + +const preview: Preview = { + parameters: { + actions: { argTypesRegex: "^on[A-Z].*" }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/, + }, + }, + }, +}; + +export default preview; diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..1fa733fd --- /dev/null +++ b/Dockerfile @@ -0,0 +1,35 @@ +### STAGE 1: Build ### + +# pull official base image +FROM node:latest AS building + +# set working directory +WORKDIR /opt/app + +# copy app +COPY . . + +# install app dependencies +RUN npm ci --legacy-peer-deps + +# setting environment variables to set version +ENV VITE_UNIVERSIME_API=/api +ARG VITE_BUILD_HASH +ENV VITE_BUILD_HASH=${VITE_BUILD_HASH} + +# Build app +RUN npm run build:docker + +FROM nginx:latest + +RUN rm -rf /usr/share/nginx/html/* + +COPY --from=building /opt/app/dist /usr/share/nginx/html/universime +COPY --from=building /opt/app/scripts/docker/run.sh / +COPY --from=building /opt/app/scripts/docker/nginx/conf.d/*.conf /etc/nginx/conf.d/ +COPY --from=building /opt/app/scripts/docker/nginx/nginx.conf /etc/nginx/ + +EXPOSE 8088 + +RUN ["chmod", "+x", "/run.sh"] +CMD ["/run.sh"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..3440f380 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# Universi.me + + +O Universi.me é um projeto de extensão coordenado pelo prof. Rodrigo Rebouças de Almeida, no Departamento de Ciências Exatas da Universidade Federal da Paraíba. + +Este código é licenciado. + +Universi.me © 2023 por Rodrigo Rebouças de Almeida está licenciado sob a licença Creative Commons Atribuição-NãoComercial-SemDerivações 4.0 Internacional. Para ver uma cópia dessa licença, visite [https://creativecommons.org/licenses/by-nc-nd/4.0/](https://creativecommons.org/licenses/by-nc-nd/4.0/). + diff --git a/__tests__/.gitkeep b/__tests__/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/__tests__/sample.test.tsx b/__tests__/sample.test.tsx new file mode 100644 index 00000000..9c395c56 --- /dev/null +++ b/__tests__/sample.test.tsx @@ -0,0 +1,18 @@ +import type { Question } from "@/types/question"; + +describe("sample tests used as examples", () => { + test("1 to equal 1", () => { + expect(1).toBe(1); + }); + + test("import type from src", () => { + const q: Question = { + feedback_id: 0, + id: 1, + title: "example", + user_create_id: 0 + }; + + expect(q.id).toBe(1); + }) +}) diff --git a/babel.config.json b/babel.config.json new file mode 100644 index 00000000..a37d440f --- /dev/null +++ b/babel.config.json @@ -0,0 +1,7 @@ +{ + "presets": [ + ["@babel/preset-env", { "targets": { "esmodules": true } }], + ["@babel/preset-react", { "runtime": "automatic" }], + "@babel/preset-typescript" + ] +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..c1ceca96 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,12 @@ +version: '3.5' + +services: + universi-front: + container_name: universi-front + build: + context: . + restart: unless-stopped + ports: + - "8088:8088" + env_file: + - .env diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 00000000..79f0bcd8 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/bash +export VITE_BUILD_HASH=$(cat /opt/app/build.hash) +exec "$@" \ No newline at end of file diff --git a/index.html b/index.html index 9454c898..8e69d5a4 100644 --- a/index.html +++ b/index.html @@ -3,6 +3,7 @@
++ Tamanho mínimo de oito caracteres +
++ Letras minúsculas e maiúsculas +
++ Números ou caracteres especiais +
++ Confirme a sua nova senha +
+Nenhuma bio
+ :{ props.profile.bio }
+ } +{ group.name }
+ +} diff --git a/src/components/ProfileInfo/ProfileInfo.less b/src/components/ProfileInfo/ProfileInfo.less new file mode 100644 index 00000000..bcc6def7 --- /dev/null +++ b/src/components/ProfileInfo/ProfileInfo.less @@ -0,0 +1,44 @@ +@import url(/src/layouts/spacing.less); +@import url(/src/layouts/utils.less); + +.profile-info-component { + @bioWrapperWidth: 15rem; + @gapWidth: 1rem; + @contentWidth: calc(@maxScreenWidth - @bioWrapperWidth - @gapWidth); + + display: grid; + grid-template-columns: max-content auto; + column-gap: @gapWidth; + + margin-top: @top-page-margin; + margin-bottom: @top-page-margin; + + width: 100%; + + .profile-bio-groups-container{ + width: @bioWrapperWidth; + } + + .profile-info-content { + width: @contentWidth; + } + + @media @onMobile { + display: flex !important; + flex-direction: column; + + .profile-bio-groups-container{ + width: 100%; + margin-bottom: 2rem; + + .profile-bio-component{ + display: none; + } + + } + + .profile-info-content { + width: 100%; + } + } +} diff --git a/src/components/ProfileInfo/ProfileInfo.tsx b/src/components/ProfileInfo/ProfileInfo.tsx new file mode 100644 index 00000000..6a2be71c --- /dev/null +++ b/src/components/ProfileInfo/ProfileInfo.tsx @@ -0,0 +1,30 @@ +import { type PropsWithChildren, type HTMLAttributes } from "react"; +import { ProfileBio, ProfileGroups } from "@/components/ProfileInfo"; + +import { type Profile } from "@/types/Profile"; +import { type Link } from "@/types/Link"; +import { type Group } from "@/types/Group"; + +import "./ProfileInfo.less"; +import { makeClassName } from "@/utils/tsxUtils"; + +export type ProfileInfoProps = PropsWithChildren<{ + profile?: Profile; + links?: Link[]; + groups?: Group[]; + organization?: Group | null; +}> & HTMLAttributes")){ + for(let line1 of line.split("
")){ + if(line1.trim() != ""+line + } + } + } + + return validValue + } + + function handleContentChange(){ + handleChange(index, object.type == FormInputs.FORMATED_TEXT ? validHtml(valueState) : valueState) + } + + return ( + <> + + { + object.type == FormInputs.LONG_TEXT ? +