64 Commits

Author SHA1 Message Date
SrJuggernaut 4e03c43ded fix: session api update 2024-07-30 18:20:11 -06:00
SrJuggernaut c979e6540f refactor: team applications 2024-07-30 18:08:53 -06:00
SrJuggernaut 7a87eac395 chore: update dependencies 2024-07-30 18:08:28 -06:00
SrJuggernaut ff0d24bbb6 feat: static applications dashboard 2024-02-16 13:08:56 -06:00
SrJuggernaut ddeed0a6ef fix: missing helper texts 2024-02-08 15:54:31 -06:00
SrJuggernaut e105edbbee fix: session related bugs 2024-02-08 15:37:57 -06:00
SrJuggernaut 9878ca7f1c feat: updated dependencies &package name 2024-02-06 20:27:24 -06:00
SrJuggernaut 7d5c0aeea9 chore: updated old formik forms to use hooks 2024-02-06 20:25:27 -06:00
SrJuggernaut 7f758d9d0b feat: updated cuenta page 2024-02-06 20:19:02 -06:00
SrJuggernaut 820865ac79 feat: useManageErrors hook 2024-02-06 20:14:59 -06:00
SrJuggernaut 345f79e53a feat: equipo pages now uses data from database package 2024-02-06 14:52:29 -06:00
SrJuggernaut 9403b28040 fix: login form recuperar contraseña 2024-02-06 14:47:46 -06:00
SrJuggernaut c21617aec3 feat: session with current user 2024-02-06 12:50:00 -06:00
SrJuggernaut 7696c4f371 fix: remove not longer used fonts 2024-02-05 14:10:43 -06:00
SrJuggernaut 84f02c9bc5 fix: api team-applications route 2024-02-05 14:08:46 -06:00
SrJuggernaut 0042cbee31 fix: fix image config 2024-02-05 12:40:00 -06:00
SrJuggernaut 71c14fee52 chore: updated dependencies 2024-01-27 14:08:36 -06:00
SrJuggernaut 21bd696a30 feat: recover password flow 2024-01-24 11:28:01 -06:00
SrJuggernaut 5f9b972983 feat: http verbs 2024-01-23 17:02:11 -06:00
SrJuggernaut 57f5f80969 feat: basic apply form 2024-01-18 22:23:21 -06:00
SrJuggernaut 984799d502 feat: metadataBase 2024-01-12 11:09:02 -06:00
SrJuggernaut 8d8b5e1646 feat: session 2024-01-11 20:57:17 -06:00
SrJuggernaut 4f37fd4734 fix: equipo div inside p 2024-01-05 15:18:23 -06:00
SrJuggernaut b7e273ae06 feat: state redux toolkit & feedback slice 2024-01-05 15:08:11 -06:00
SrJuggernaut ab82d0797d fix: remove unused logs 2024-01-04 22:50:43 -06:00
SrJuggernaut 8c95537324 feat: static login & register pages 2024-01-04 22:24:58 -06:00
SrJuggernaut a6e072703d feat: update dependencies 2024-01-04 22:11:10 -06:00
SrJuggernaut 7d39bb3d89 feat: improve ui components 2024-01-04 21:46:10 -06:00
SrJuggernaut 0c74c0a0a9 feat: move appwrite to entgamers-database package 2024-01-03 17:31:22 -06:00
SrJuggernaut b393e0cdb0 feat: static equipo unirse 2024-01-03 15:03:08 -06:00
SrJuggernaut ba466dfd80 chore: update dependencies 2024-01-01 18:34:42 -06:00
SrJuggernaut ee8bf42aad chore: moving from yarn to bun 2024-01-01 17:52:41 -06:00
SrJuggernaut b2756b0654 chore: remove old mui types 2024-01-01 17:52:10 -06:00
SrJuggernaut b01e211acb feat: static unirse 2023-10-06 12:27:28 -06:00
SrJuggernaut 33a3e7bb70 feat: static pages 2023-09-19 21:20:33 -06:00
SrJuggernaut a8c579b94e feat: static homepage 2023-09-18 14:29:54 -06:00
SrJuggernaut bde70454dc feat: nextjs13 boilerplate 2023-09-17 13:41:24 -06:00
SrJuggernaut 2135a4b55d feat: start over and layout 2023-09-16 21:48:09 -06:00
SrJuggernaut eb334f6357 feat: eslint update 2023-09-15 12:36:07 -06:00
SrJuggernaut 14b52a7800 fix: remove bundle analyzer 2023-09-14 21:15:53 -06:00
SrJuggernaut f11ae1c4f3 revert: revert to yarn to deploy 2023-09-14 21:08:33 -06:00
SrJuggernaut f5a9a88f84 fix: pm2 script 2023-09-14 14:52:25 -06:00
SrJuggernaut f59a7cc091 fix: interpreter to use pm2 2 2023-09-14 14:49:04 -06:00
SrJuggernaut 3a831acaee fix: interpreter to use pm2 2023-09-14 14:39:51 -06:00
SrJuggernaut b514c6bc6f fix: bun doesnt run on pm2 2023-09-14 14:21:14 -06:00
SrJuggernaut ce87aa5ee3 feat: moving deployments to bun 2023-09-14 14:14:12 -06:00
SrJuggernaut b26d5d8eba chore: updated dependencies 2023-09-14 13:01:22 -06:00
SrJuggernaut 390f8bc858 feat: riot review 2023-07-11 15:46:34 -06:00
SrJuggernaut d926d3a5ef fix: github action name, wrong triggers 2023-01-04 15:47:45 -06:00
SrJuggernaut fdefa84ec7 fix: github action naming 2023-01-04 15:46:14 -06:00
SrJuggernaut 9db5e5cebf feat: setup github action to run on new server 2023-01-04 15:44:18 -06:00
SrJuggernaut 35105441cb docs: deploy env vars 2022-10-09 13:56:41 -05:00
SrJuggernaut 7986456b9c fix: production git ref 2022-10-09 13:20:42 -05:00
SrJuggernaut f9aea7eea4 fix: glass text contrast 2022-10-01 13:34:31 -05:00
SrJuggernaut a68098e7e2 ci: use yarn instead npm 2022-10-01 13:33:29 -05:00
SrJuggernaut 864ff91255 fix: server use isomorphic-fetch 2022-09-30 19:32:40 -05:00
SrJuggernaut c69a166c1f revert: deploy as sudo
Refs: 624b225
2022-09-30 18:23:38 -05:00
SrJuggernaut 731c9b8962 fix: pass only required env to deploy 2022-09-30 17:50:41 -05:00
SrJuggernaut 624b2251c4 feat: post deploy as sudo 2022-09-30 13:57:27 -05:00
SrJuggernaut b73cc51e08 fix: pass environment to actions 2022-09-30 13:41:56 -05:00
SrJuggernaut a35e99f8ff ci: deploy using pm2
* ci: pm2 configuration file

* ci: github action deploy preview

* ci: github action deploy production

* ci: env variables now pass to pm2
2022-09-29 21:54:58 -05:00
SrJuggernaut 4f8c4f6492 docs: initial documentation 2022-09-28 18:09:10 -05:00
SrJuggernaut c3dae929c6 feat: static site
* feat: mui support & basic theming

* feat: entgamers favicon

* feat: public images until dynamic content can be used

* feat: entgamers & gaming assets

* feat: eslint extra rules

* feat: mui theme modifications

* feat: fontawesome, gsap, bundle analyzer

* feat: common interfaces

* feat: basic layout

* chore: upadted dependencies

* chore: updated dependencies

* feat: updated link styles

* feat: layout now have better interfaces

* feat: basic seo component

* feat: static website

* feat: env variable rules in .gitignore

* feat: added lint to pre-commit
2022-09-26 12:01:26 -05:00
SrJuggernaut 8573d61066 Initial commit from Create Next App 2022-08-13 11:29:32 -05:00
65 changed files with 596 additions and 811 deletions
-134
View File
@@ -1,134 +0,0 @@
############################################################
# Production-ready .dockerignore for a Next.js app
# Keeps Docker builds fast, lean, and free of development files.
############################################################
# Dependencies (installed inside Docker, never copied)
node_modules/
.pnpm-store/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# Next.js build outputs (always generated during `next build`)
.next/
out/
dist/
build/
.vercel/
# Tests and testing output (not needed in production images)
coverage/
.nyc_output/
__tests__/
__mocks__/
jest/
cypress/
cypress/screenshots/
cypress/videos/
playwright-report/
test-results/
.vitest/
vitest.config.*
jest.config.*
cypress.config.*
playwright.config.*
*.test.*
*.spec.*
# Local development and editor files
.git/
.gitignore
.gitattributes
.vscode/
.idea/
*.swp
*.swo
*~
*.log
# Environment variables (only commit template files)
.env
.env*.local
.env.development
.env.test
.env.production.local
# Docker configuration files (not needed inside build context)
Dockerfile*
.dockerignore
compose.yaml
compose.yml
docker-compose*.yaml
docker-compose*.yml
# Documentation
*.md
docs/
# CI/CD configuration files
.github/
.gitlab-ci.yml
.travis.yml
.circleci/
Jenkinsfile
# Cache directories and temporary data
.cache/
.parcel-cache/
.eslintcache
.stylelintcache
.swc/
.turbo/
.tmp/
.temp/
# TypeScript build metadata
*.tsbuildinfo
# Sensitive or unnecessary configuration files
*.pem
.editorconfig
.prettierrc*
prettier.config.*
.eslintrc*
eslint.config.*
.stylelintrc*
stylelint.config.*
.babelrc*
*.iml
*.ipr
*.iws
# OS-specific junk
.DS_Store
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
Desktop.ini
# AI/ML tool metadata and configs
.cursor/
.cursorrules
.copilot/
.copilotignore
.github/copilot/
.gemini/
.anthropic/
.kiro
.claude
AGENTS.md
.agents/
# AI-generated temp files
*.aider*
*.copilot*
*.chatgpt*
*.claude*
*.gemini*
*.openai*
*.anthropic*
+4 -1
View File
@@ -1,3 +1,7 @@
# App variables
SITE_NAME="EntGamers"
# Deployment variables
APP_NAME=""
@@ -19,6 +23,5 @@ APPWRITE_API_KEY=""
# Website Variables
SITE_NAME="EntGamers"
NEXT_PUBLIC_SITE_URL="https://entgamers.com"
IMAGE_DOMAINS="https://domain.com,http://another.domain.com/route/"
+1
View File
@@ -0,0 +1 @@
src/styled-system
+55
View File
@@ -0,0 +1,55 @@
{
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": [
"next/core-web-vitals",
"standard-with-typescript",
"plugin:react/recommended"
],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"react"
],
"rules": {
"react/react-in-jsx-scope": "off",
"react/jsx-uses-react": "off",
"indent": "off",
"@typescript-eslint/indent": [
"error",
2,
{
"SwitchCase": 1
}
],
"react/jsx-indent": [
"error",
2
],
"no-use-before-define": "off",
"@typescript-eslint/no-use-before-define": [
"error"
],
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_"
}
],
"react-hooks/exhaustive-deps": "off",
"react/no-unknown-property": [
"error",
{
"ignore": [
"css"
]
}
]
}
}
+33
View File
@@ -0,0 +1,33 @@
name: CI deploy preview
on:
push:
branches: ["preview"]
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
environment: preview
steps:
- uses: actions/checkout@v3
- uses: oven-sh/setup-bun@v1
- uses: kielabokkie/ssh-key-and-known-hosts-action@v1
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
ssh-host: ${{ secrets.DEPLOY_HOST }}
- name: Install pm2
run: bun install pm2 -g
shell: bash
- name: Deploy using pm2
run: pm2 deploy ecosystem.config.js preview
env:
# Deploy environment variables
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
SSH_USERNAME: ${{ secrets.SSH_USERNAME }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
# App environment variables
APP_NAME: ${{ secrets.APP_NAME }}
SITE_NAME: ${{ secrets.SITE_NAME }}
PORT: ${{ secrets.PORT }}
DISCORD_JOIN_WEBHOOK_URL: ${{ secrets.DISCORD_JOIN_WEBHOOK_URL }}
shell: bash
+33
View File
@@ -0,0 +1,33 @@
name: CI deploy production
on:
push:
branches: ["production"]
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v3
- uses: oven-sh/setup-bun@v1
- uses: kielabokkie/ssh-key-and-known-hosts-action@v1
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
ssh-host: ${{ secrets.DEPLOY_HOST }}
- name: Install pm2
run: bun install pm2 -g
shell: bash
- name: Deploy using pm2
run: pm2 deploy ecosystem.config.js production
env:
# Deploy environment variables
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
SSH_USERNAME: ${{ secrets.SSH_USERNAME }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
# App environment variables
APP_NAME: ${{ secrets.APP_NAME }}
SITE_NAME: ${{ secrets.SITE_NAME }}
PORT: ${{ secrets.PORT }}
DISCORD_JOIN_WEBHOOK_URL: ${{ secrets.DISCORD_JOIN_WEBHOOK_URL }}
shell: bash
+31
View File
@@ -0,0 +1,31 @@
name: CI setup preview
on:
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
environment: preview
steps:
- uses: actions/checkout@v3
- uses: oven-sh/setup-bun@v1
- uses: kielabokkie/ssh-key-and-known-hosts-action@v1
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
ssh-host: ${{ secrets.DEPLOY_HOST }}
- name: Install pm2
run: bun install pm2 -g
shell: bash
- name: Deploy using pm2
run: pm2 deploy ecosystem.config.js preview setup
env:
# Deploy environment variables
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
SSH_USERNAME: ${{ secrets.SSH_USERNAME }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
# App environment variables
APP_NAME: ${{ secrets.APP_NAME }}
SITE_NAME: ${{ secrets.SITE_NAME }}
PORT: ${{ secrets.PORT }}
DISCORD_JOIN_WEBHOOK_URL: ${{ secrets.DISCORD_JOIN_WEBHOOK_URL }}
shell: bash
+31
View File
@@ -0,0 +1,31 @@
name: CI setup production
on:
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v3
- uses: oven-sh/setup-bun@v1
- uses: kielabokkie/ssh-key-and-known-hosts-action@v1
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
ssh-host: ${{ secrets.DEPLOY_HOST }}
- name: Install pm2
run: bun install pm2 -g
shell: bash
- name: Deploy using pm2
run: pm2 deploy ecosystem.config.js production setup
env:
# Deploy environment variables
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
SSH_USERNAME: ${{ secrets.SSH_USERNAME }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
# App environment variables
APP_NAME: ${{ secrets.APP_NAME }}
SITE_NAME: ${{ secrets.SITE_NAME }}
PORT: ${{ secrets.PORT }}
DISCORD_JOIN_WEBHOOK_URL: ${{ secrets.DISCORD_JOIN_WEBHOOK_URL }}
shell: bash
+4 -1
View File
@@ -1 +1,4 @@
bunx --no -- commitlint --edit "${1}"
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx --no -- commitlint --edit "${1}"
-9
View File
@@ -1,9 +0,0 @@
// Skip Husky install in production and CI
if (process.env.NODE_ENV === 'production' || process.env.CI === 'true') {
process.exit(0)
}
const husky = (await import('husky')).default
console.log(husky())
-1
View File
@@ -1 +0,0 @@
bunx lint-staged --config lint-staged.config.ts
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run lint
-52
View File
@@ -1,52 +0,0 @@
FROM oven/bun:1.3-alpine AS builder
WORKDIR /app
COPY . .
ARG NEXT_PUBLIC_APPWRITE_ENDPOINT=""
ARG NEXT_PUBLIC_APPWRITE_PROJECT_ID=""
ARG SITE_NAME="EntGamers"
ARG NEXT_PUBLIC_SITE_URL="https://entgamers.pro"
ARG IMAGE_DOMAINS="https://api.entgamers.pro"
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV CI=1
ENV HUSKY=0
ENV DOCKER_BUILD="true"
RUN bun install --frozen-lockfile
RUN --mount=type=secret,id=APPWRITE_API_KEY,env=APPWRITE_API_KEY \
NEXT_PUBLIC_APPWRITE_ENDPOINT=${NEXT_PUBLIC_APPWRITE_ENDPOINT} \
NEXT_PUBLIC_APPWRITE_PROJECT_ID=${NEXT_PUBLIC_APPWRITE_PROJECT_ID} \
SITE_NAME=${SITE_NAME} \
NEXT_PUBLIC_SITE_URL=${NEXT_PUBLIC_SITE_URL} \
IMAGE_DOMAINS=${IMAGE_DOMAINS} \
bun run build
FROM oven/bun:1.3-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
ENV NEXT_TELEMETRY_DISABLED=1
COPY --from=builder --chown=bun:bun /app/public ./public
COPY --from=builder --chown=bun:bun /app/.next/standalone ./
COPY --from=builder --chown=bun:bun /app/.next/static ./.next/static
USER bun
EXPOSE 3000
CMD ["bun", "server.js"]
BIN
View File
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
module.exports = { extends: ['@commitlint/config-conventional'] }
-5
View File
@@ -1,5 +0,0 @@
import type { UserConfig } from '@commitlint/types'
const Configuration: UserConfig = { extends: ['@commitlint/config-conventional'] }
export default Configuration
+18 -31
View File
@@ -2,55 +2,42 @@ module.exports = {
apps: [
{
name: process.env.APP_NAME || 'entgamers-website',
script: 'bun',
script: 'yarn',
args: 'run start',
env: {
NODE_ENV: 'production',
PORT: process.env.PORT || 3000,
NEXT_PUBLIC_APPWRITE_ENDPOINT: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT,
NEXT_PUBLIC_APPWRITE_PROJECT_ID: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID,
APPWRITE_API_KEY: process.env.APPWRITE_API_KEY,
SITE_NAME: process.env.SITE_NAME,
NEXT_PUBLIC_SITE_URL: process.env.NEXT_PUBLIC_SITE_URL,
IMAGE_DOMAINS: process.env.IMAGE_DOMAINS
DISCORD_JOIN_WEBHOOK_URL: process.env.DISCORD_JOIN_WEBHOOK_URL
}
}
],
deploy: {
production: {
'user': process.env.SSH_USERNAME,
'host': process.env.DEPLOY_HOST,
'ref': 'origin/production',
'repo': 'https://github.com/SrJuggernaut/entgamers_pro',
'path': process.env.DEPLOY_PATH,
user: process.env.SSH_USERNAME,
host: process.env.DEPLOY_HOST,
ref: 'origin/production',
repo: 'https://github.com/SrJuggernaut/entgamers_pro',
path: process.env.DEPLOY_PATH,
'post-deploy': 'pm2 --silent startOrRestart ecosystem.config.js',
'env': {
env: {
APP_NAME: process.env.APP_NAME,
PORT: process.env.PORT,
NEXT_PUBLIC_APPWRITE_ENDPOINT: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT,
NEXT_PUBLIC_APPWRITE_PROJECT_ID: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID,
APPWRITE_API_KEY: process.env.APPWRITE_API_KEY,
SITE_NAME: process.env.SITE_NAME,
NEXT_PUBLIC_SITE_URL: process.env.NEXT_PUBLIC_SITE_URL,
IMAGE_DOMAINS: process.env.IMAGE_DOMAINS
DISCORD_JOIN_WEBHOOK_URL: process.env.DISCORD_JOIN_WEBHOOK_URL
}
},
preview: {
'user': process.env.SSH_USERNAME,
'host': process.env.DEPLOY_HOST,
'ref': 'origin/preview',
'repo': 'https://github.com/SrJuggernaut/entgamers_pro',
'path': process.env.DEPLOY_PATH,
user: process.env.SSH_USERNAME,
host: process.env.DEPLOY_HOST,
ref: 'origin/preview',
repo: 'https://github.com/SrJuggernaut/entgamers_pro',
path: process.env.DEPLOY_PATH,
'post-deploy': 'pm2 --silent startOrRestart ecosystem.config.js',
'env': {
env: {
APP_NAME: process.env.APP_NAME,
PORT: process.env.PORT,
NEXT_PUBLIC_APPWRITE_ENDPOINT: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT,
NEXT_PUBLIC_APPWRITE_PROJECT_ID: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID,
APPWRITE_API_KEY: process.env.APPWRITE_API_KEY,
SITE_NAME: process.env.SITE_NAME,
NEXT_PUBLIC_SITE_URL: process.env.NEXT_PUBLIC_SITE_URL,
IMAGE_DOMAINS: process.env.IMAGE_DOMAINS
DISCORD_JOIN_WEBHOOK_URL: process.env.DISCORD_JOIN_WEBHOOK_URL
}
}
}
-98
View File
@@ -1,98 +0,0 @@
import eslintJs from '@eslint/js'
import nextPlugin from '@next/eslint-plugin-next'
import jsxA11yPlugin from 'eslint-plugin-jsx-a11y'
import reactPlugin from 'eslint-plugin-react'
import reactHooksPlugin from 'eslint-plugin-react-hooks'
import { defineConfig, globalIgnores } from 'eslint/config'
import globals from 'globals'
import tseslint from 'typescript-eslint'
import stylisticPlugin from '@stylistic/eslint-plugin'
export default defineConfig([
globalIgnores([
'node_modules/',
'public/', 'src/styled-system/**/*', '.next/**',
'out/**',
'build/**',
'next-env.d.ts']),
{
name: 'entgamers_pro/globals',
languageOptions: {
globals: {
...globals.browser,
...globals.node
}
}
},
{
name: 'project/eslint-js',
files: ['**/*.{js,mjs,ts,tsx}'],
...eslintJs.configs.recommended
},
{
name: 'project/typescript',
files: ['**/*.{ts,tsx}'],
extends: [
...tseslint.configs.recommended
],
rules: {
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }]
}
},
{
name: 'project/react-next',
files: ['**/*.{jsx,tsx}'],
plugins: {
'react': reactPlugin,
'react-hooks': reactHooksPlugin,
'jsx-a11y': jsxA11yPlugin,
'@next/next': nextPlugin
},
rules: {
...reactPlugin.configs.recommended.rules,
...reactPlugin.configs['jsx-runtime'].rules,
...reactHooksPlugin.configs['recommended-latest'].rules,
...jsxA11yPlugin.configs.strict.rules,
...nextPlugin.configs.recommended.rules,
...nextPlugin.configs['core-web-vitals'].rules,
'react/react-in-jsx-scope': 'off',
'react/prop-types': 'off',
'react/no-unknown-property': 'off',
'react/jsx-no-target-blank': 'off',
'jsx-a11y/alt-text': ['warn', { elements: ['img'], img: ['Image'] }],
'jsx-a11y/media-has-caption': 'warn'
},
settings: {
react: {
version: '19'
}
}
},
{
name: 'project/stylistic',
files: ['**/*.{js,mjs,ts,tsx}'],
plugins: {
'@stylistic': stylisticPlugin
},
rules: {
// Remove legacy formatting rules from ESLint core
...stylisticPlugin.configs['disable-legacy'].rules,
// Add recommended stylistic rules
...stylisticPlugin.configs.recommended.rules,
'@stylistic/indent': ['warn', 2],
'@stylistic/quotes': ['warn', 'single', {
avoidEscape: true,
allowTemplateLiterals: 'always'
}],
'@stylistic/semi': ['warn', 'never'],
'@stylistic/comma-dangle': ['warn', 'never'],
'@stylistic/arrow-parens': ['warn', 'always', {
requireForBlockBody: true
}],
'@stylistic/brace-style': ['warn', '1tbs', {
allowSingleLine: true
}]
}
}
])
-7
View File
@@ -1,7 +0,0 @@
import type { Configuration } from 'lint-staged'
const config: Configuration = {
'*.{js,jsx,ts,tsx}': 'eslint --fix'
}
export default config
+1 -2
View File
@@ -1,6 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
// see https://nextjs.org/docs/basic-features/typescript for more information.
+15
View File
@@ -0,0 +1,15 @@
const imageDomains = (process.env.IMAGE_DOMAINS ?? '').split(',').map(domain => {
const getDataRegex = /(?<protocol>[\w]+)?:\/\/(?<hostname>[\w.-]+)?((?<=[\d]{0,4}):(?<port>[\d]{0,4}))?\/?(?<pathname>.*)?$/
const groups = getDataRegex.exec(domain).groups ?? {}
return groups
})
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
images: {
remotePatterns: imageDomains
}
}
module.exports = nextConfig
-17
View File
@@ -1,17 +0,0 @@
import type { NextConfig } from 'next'
const imageDomains = (process.env.IMAGE_DOMAINS ?? '').split(',').map((domain) => {
return new URL(domain)
})
const IS_DOCKER_BUILD = process.env.DOCKER_BUILD === 'true'
const nextConfig: NextConfig = {
output: IS_DOCKER_BUILD ? 'standalone' : undefined,
reactStrictMode: true,
images: {
remotePatterns: imageDomains
}
}
module.exports = nextConfig
+32 -27
View File
@@ -5,51 +5,56 @@
"scripts": {
"develop": "next dev",
"build": "next build",
"prestart": "bun install && next build",
"start": "next start",
"lint": "eslint .",
"prepare": "panda codegen && bun ./.husky/install.mts"
"lint": "next lint",
"prepare": "panda codegen && husky install"
},
"dependencies": {
"@fontsource/open-sans": "^5.0.20",
"@fontsource/permanent-marker": "^5.0.8",
"@fortawesome/fontawesome-svg-core": "^7.2.0",
"@fortawesome/free-brands-svg-icons": "^7.2.0",
"@fortawesome/free-solid-svg-icons": "^7.2.0",
"@fortawesome/react-fontawesome": "^3.3.0",
"@fortawesome/fontawesome-svg-core": "^6.5.1",
"@fortawesome/free-brands-svg-icons": "^6.5.1",
"@fortawesome/free-solid-svg-icons": "^6.5.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@reduxjs/toolkit": "^2.0.1",
"@stylistic/eslint-plugin": "^5.10.0",
"@tanstack/match-sorter-utils": "^8.11.8",
"@tanstack/react-table": "^8.19.3",
"appwrite": "^13.0.1",
"date-fns": "^4.1.0",
"date-fns": "^3.3.1",
"entgamers-database": "0.0.26",
"entgamers-panda-preset": "0.1.5",
"formik": "^2.4.5",
"framer-motion": "^12.38.0",
"framer-motion": "^10.17.6",
"isomorphic-fetch": "^3.0.0",
"lint-staged": "^16.4.0",
"next": "16.2.2",
"next": "^14.0.4",
"node-appwrite": "^11.1.0",
"react": "19.2.4",
"react-dom": "19.2.4",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-redux": "^9.0.4",
"sharp": "^0.34.5",
"sharp": "^0.33.1",
"yup": "^1.3.3"
},
"devDependencies": {
"@commitlint/cli": "^20.5.0",
"@commitlint/config-conventional": "^20.5.0",
"@eslint/js": "^10.0.1",
"@pandacss/dev": "^1.9.1",
"@types/bun": "^1.3.11",
"@commitlint/cli": "^18.4.4",
"@commitlint/config-conventional": "^18.4.4",
"@pandacss/dev": "^0.23.0",
"@types/isomorphic-fetch": "^0.0.39",
"@types/react": "19.2.14",
"@types/react-dom": "19.2.3",
"eslint": "^10.1.0",
"eslint-config-next": "16.2.2",
"eslint-plugin-react": "^7.37.5",
"husky": "^9.1.7",
"typescript": "*",
"typescript-eslint": "^8.58.0"
"@types/node": "^20.10.6",
"@types/react": "^18.2.46",
"@types/react-dom": "^18.2.18",
"@typescript-eslint/eslint-plugin": "^6.4.0",
"@typescript-eslint/parser": "^5.38.0",
"eslint": "^8.0.1",
"eslint-config-next": "latest",
"eslint-config-standard": "^17.0.0",
"eslint-config-standard-with-typescript": "latest",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-n": "^15.0.0 || ^16.0.0 ",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-react": "latest",
"husky": "^8.0.3",
"typescript": "*"
}
}
+1 -1
View File
@@ -22,7 +22,7 @@ const Clanes: FC = () => {
<div
className={card({ variant: 'glass' }).content}
>
<Typography variant="h2" align="center">Clanes</Typography>
<Typography variant="h2" align='center'>Clanes</Typography>
<div
className={css({
display: 'grid',
+3 -3
View File
@@ -9,11 +9,11 @@ import { alert } from '@/styled-system/recipes/alert'
import { faTimes } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { AnimatePresence, motion } from 'framer-motion'
import type { FC } from 'react'
import { type FC } from 'react'
import { createPortal } from 'react-dom'
const FeedbackConsumer: FC = () => {
const { alerts } = useAppSelector((state) => state.feedback)
const { alerts } = useAppSelector(state => state.feedback)
const dispatch = useAppDispatch()
return (
<>
@@ -55,7 +55,7 @@ const FeedbackConsumer: FC = () => {
className={alert().closeButton}
onClick={() => dispatch(removeAlert(currentAlert.id))}
>
<FontAwesomeIcon icon={faTimes} size="sm" />
<FontAwesomeIcon icon={faTimes} fixedWidth size='sm'/>
</IconButton>
<Typography variant="h3" component="div">
{currentAlert.title}
+9 -9
View File
@@ -111,20 +111,20 @@ const Hero: FC = () => {
color: 'primary',
size: 'large'
}), css({
'position': 'absolute',
'bottom': '45px',
'right': '50%',
'animationName': 'bounce',
'animationDuration': '1s',
'animationIterationCount': 'infinite',
'transform': 'translateX(50%)',
'zIndex': 1,
position: 'absolute',
bottom: '45px',
right: '50%',
animationName: 'bounce',
animationDuration: '1s',
animationIterationCount: 'infinite',
transform: 'translateX(50%)',
zIndex: 1,
'&:hover': {
animationPlayState: 'paused'
}
}))}
>
<FontAwesomeIcon icon={faArrowDown} size="lg" />
<FontAwesomeIcon icon={faArrowDown} size='lg' fixedWidth />
</a>
</section>
)
+10 -6
View File
@@ -5,7 +5,7 @@ import { setClanes, setCurrentUser, setSession, setStatus } from '@/state/sessio
import { AppwriteException } from 'appwrite'
import { getClanes } from 'entgamers-database/frontend/clanes'
import { getCurrentUser, getSession } from 'entgamers-database/frontend/session'
import { type FC, useCallback, useEffect } from 'react'
import { useCallback, useEffect, type FC } from 'react'
const SessionConsumer: FC = () => {
const { status, session, user, clanes } = useAppSelector((state) => state.session)
@@ -13,6 +13,7 @@ const SessionConsumer: FC = () => {
const ensureSession = useCallback(async () => {
try {
if (status !== 'initializing' || session !== undefined) return
dispatch(setStatus('loading'))
const currentSession = await getSession('current')
const currentUser = await getCurrentUser()
@@ -25,17 +26,16 @@ const SessionConsumer: FC = () => {
} finally {
dispatch(setStatus('idle'))
}
}, [dispatch])
}, [])
useEffect(() => {
if (status !== 'initializing' || session !== undefined) return
ensureSession()
.catch((error) => {
if (error instanceof AppwriteException) {
console.error(error)
}
})
}, [status, session, ensureSession])
}, [])
useEffect(() => {
if (user !== undefined && clanes === undefined) {
@@ -51,7 +51,11 @@ const SessionConsumer: FC = () => {
} else if (user === undefined && clanes !== undefined) {
dispatch(setClanes())
}
}, [user, clanes, dispatch])
return null
}, [user])
return (
<>
</>
)
}
export default SessionConsumer
+1 -1
View File
@@ -52,7 +52,7 @@ const Social: FC = () => {
<div
className={card({ variant: 'glass' }).content}
>
<Typography variant="h2" align="center">Redes Sociales</Typography>
<Typography variant="h2" align='center'>Redes Sociales</Typography>
<Typography variant="body1">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptate deleniti dolore quas sed nemo sit, officia in rem nesciunt quisquam possimus ab! Labore sed reprehenderit quae, hic earum tempora placeat cumque id eos itaque perferendis nulla officia fuga porro, quis, unde facere accusamus repudiandae non?
</Typography>
+1 -1
View File
@@ -84,7 +84,7 @@ const Team: FC = () => {
className={iconButton()}
href={socialNetwork.url}
>
<FontAwesomeIcon icon={socialNetwork.icon} />
<FontAwesomeIcon icon={socialNetwork.icon} fixedWidth />
</a>
))}
</div>
+14 -55
View File
@@ -3,7 +3,7 @@ import { css } from '@/styled-system/css'
import { Container } from '@/styled-system/jsx'
import { faChevronRight } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import type { FC } from 'react'
import { type FC } from 'react'
const ClanesPage: FC = () => {
return (
@@ -21,78 +21,37 @@ const ClanesPage: FC = () => {
<Typography variant="h2">Beneficios de los clanes</Typography>
<Typography variant="body1">La intención de EntGamers es brindar beneficios a los clanes que les permitan operar en un ambiente de comunicación y colaboración.</Typography>
<ul className="fa-ul">
<li>
<span className="fa-li"><FontAwesomeIcon icon={faChevronRight} /></span>
{' '}
Espacio en el servidor de Discord.
</li>
<li>
<span className="fa-li"><FontAwesomeIcon icon={faChevronRight} /></span>
{' '}
Apoyo de la administración con proyectos y eventos.
</li>
<li>
<span className="fa-li">
<FontAwesomeIcon icon={faChevronRight} />
</span>
{' '}
Apoyo del equipo de moderación.
</li>
<li><FontAwesomeIcon icon={faChevronRight} listItem /> Espacio en el servidor de Discord.</li>
<li><FontAwesomeIcon icon={faChevronRight} listItem /> Apoyo de la administración con proyectos y eventos.</li>
<li><FontAwesomeIcon icon={faChevronRight} listItem /> Apoyo del equipo de moderación.</li>
</ul>
</div>
<div>
<Typography variant="h2">Requisitos para formar un clan</Typography>
<Typography variant="body1">Todos los clanes deben cumplir con los siguientes requisitos:</Typography>
<ul className="fa-ul">
<li>
<span className="fa-li">
<FontAwesomeIcon icon={faChevronRight} />
</span>
{' '}
Tener un encargado.
</li>
<li>
<span className="fa-li">
<FontAwesomeIcon icon={faChevronRight} />
</span>
{' '}
Fomentar el compañerismo y la comunidad.
</li>
<li>
<span className="fa-li">
<FontAwesomeIcon icon={faChevronRight} />
</span>
{' '}
Aportar contenido de forma periódica para la comunidad.
</li>
<li>
<span className="fa-li">
<FontAwesomeIcon icon={faChevronRight} />
</span>
{' '}
Realizar al menos una actividad mensual con los integrantes.
</li>
<li><FontAwesomeIcon icon={faChevronRight} listItem /> Tener un encargado.</li>
<li><FontAwesomeIcon icon={faChevronRight} listItem /> Fomentar el compañerismo y la comunidad.</li>
<li><FontAwesomeIcon icon={faChevronRight} listItem /> Aportar contenido de forma periódica para la comunidad.</li>
<li><FontAwesomeIcon icon={faChevronRight} listItem /> Realizar al menos una actividad mensual con los integrantes.</li>
</ul>
</div>
</div>
<Typography variant="h2">Clanes activos</Typography>
<div
className={css({
'backgroundColor': 'info',
'color': 'info.contrast',
'borderRadius': 'medium',
'padding': 'medium',
'marginBlock': 'medium',
backgroundColor: 'info',
color: 'info.contrast',
borderRadius: 'medium',
padding: 'medium',
marginBlock: 'medium',
'& a': {
color: 'info.contrast',
fontWeight: 'bold'
}
})}
>
Esta sección está en construcción. Puedes ver los clanes activos en nuestro
{' '}
<a href="http://discord.gg/nqwzHJC">Servidor de Discord</a>
.
Esta sección está en construcción. Puedes ver los clanes activos en nuestro <a href="http://discord.gg/nqwzHJC">Servidor de Discord</a>.
</div>
</Container>
)
+3 -5
View File
@@ -44,7 +44,7 @@ const CuentaTabs: FC = () => {
>
<AnimatePresence
initial={false}
mode="wait"
mode='wait'
>
{currentTab === 'login' && (
<motion.div
@@ -52,8 +52,7 @@ const CuentaTabs: FC = () => {
initial={{ opacity: 0, x: '-100%' }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: '100%' }}
key="login"
>
key="login">
<UpdateEmail />
<UpdatePassword />
</motion.div>
@@ -64,8 +63,7 @@ const CuentaTabs: FC = () => {
initial={{ opacity: 0, x: '-100%' }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: '100%' }}
key="perfil"
>
key="perfil">
<UpdateUserName />
<UpdateUserPreferences />
</motion.div>
+3 -2
View File
@@ -68,7 +68,7 @@ const UpdateUserName: FC = () => {
})
.catch(console.error)
}
}, [status, session, user, formik])
}, [status, session, user])
if (status !== 'idle' || session === undefined) {
// TODO: Replace with Skeleton
@@ -99,7 +99,8 @@ const UpdateUserName: FC = () => {
<Typography variant="caption" color="danger">{formik.errors.name}</Typography>
)}
</FormGroup>
<FormGroup>
<FormGroup
>
<Button
type="submit"
disabled={formik.isSubmitting || !formik.isValid}
+6 -6
View File
@@ -55,7 +55,7 @@ const UpdateUserPreferences: FC = () => {
})
.catch(console.error)
}
}, [status, user, formik, session])
}, [status, session])
if (status !== 'idle' || session === undefined) {
// TODO: Replace with Skeleton
@@ -65,7 +65,7 @@ const UpdateUserPreferences: FC = () => {
return (
<>
<Typography
variant="h3"
variant='h3'
>
Preferencias
</Typography>
@@ -74,13 +74,13 @@ const UpdateUserPreferences: FC = () => {
>
<FormGroup>
<label
htmlFor="bio"
htmlFor='bio'
>
Biografia
</label>
<TextArea
id="bio"
name="bio"
id='bio'
name='bio'
value={formik.values.bio}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
@@ -96,7 +96,7 @@ const UpdateUserPreferences: FC = () => {
{/* TODO: Add Profile Picture and Social Links fields */}
<FormGroup>
<Button
type="submit"
type='submit'
disabled={formik.isSubmitting || !formik.isValid}
fullWidth
>
+2 -2
View File
@@ -1,6 +1,6 @@
import Typography from '@/components/ui/Typography'
import { Container } from '@/styled-system/jsx'
import type { FC } from 'react'
import { type FC } from 'react'
import CuentaTabs from './CuentaTabs'
const CuentaPage: FC = () => {
@@ -10,7 +10,7 @@ const CuentaPage: FC = () => {
<Typography variant="body1">
Desde aquí puedes administrar las preferencias y ajustes de tu cuenta.
</Typography>
<CuentaTabs />
<CuentaTabs/>
</Container>
)
}
@@ -40,7 +40,7 @@ const DashboardTabs: FC = () => {
>
<AnimatePresence
initial={false}
mode="wait"
mode='wait'
>
{currentTab === undefined && (
<motion.div
@@ -17,7 +17,7 @@ const ApplicationsFilter: FC<ApplicationsFilterProps> = ({ column }) => {
<StatusSelector
id={`${column.id}-status-filter`}
value={columnFilterValue as TeamApplicationStatus}
onChange={(value) => { column.setFilterValue(value) }}
onChange={value => { column.setFilterValue(value) }}
allowEmpty
/>
)
@@ -26,7 +26,7 @@ const ApplicationsFilter: FC<ApplicationsFilterProps> = ({ column }) => {
<RoleSelector
id={`${column.id}-role-filter`}
value={columnFilterValue as TeamApplicationRole}
onChange={(value) => { column.setFilterValue(value) }}
onChange={value => { column.setFilterValue(value) }}
allowEmpty
/>
)
@@ -36,7 +36,7 @@ const ApplicationsFilter: FC<ApplicationsFilterProps> = ({ column }) => {
fullWidth
type="text"
value={(columnFilterValue ?? '') as string}
onChange={(value) => { column.setFilterValue(value) }}
onChange={value => { column.setFilterValue(value) }}
placeholder="Buscar..."
className="w-36 border shadow rounded"
list={column.id + 'list'}
@@ -3,7 +3,7 @@ import { Table, TableBody, TableCell, TableContainer, TableHead, TableHeadCell,
import useManageError from '@/hooks/useManageError'
import { css } from '@/styled-system/css'
import { formatDate } from '@/utilities/date'
import type { TeamApplication, TeamApplicationList } from '@/utilities/teamApplication'
import { type TeamApplication, type TeamApplicationList } from '@/utilities/teamApplication'
import { faChevronLeft, faChevronRight, faSort, faSortAsc, faSortDesc } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { createColumnHelper, flexRender, getCoreRowModel, useReactTable, type ColumnFiltersState, type PaginationState, type RowData, type SortingState } from '@tanstack/react-table'
@@ -29,7 +29,7 @@ const columns = [
columnHelper.accessor('status', {
header: 'Estado',
cell: StatusUpdater,
getUniqueValues() {
getUniqueValues () {
return ['Pending', 'Accepted', 'Rejected']
}
}),
@@ -125,7 +125,7 @@ const ApplicationsList: FC = () => {
if (error instanceof Error && error.name === 'AbortError') return
manageError(error, 'Error al obtener las aplicaciones', 'Error desconocido al obtener las aplicaciones', 'error')
})
}, [pagination, sorting, columnFilters, manageError])
}, [pagination, sorting, columnFilters])
// TODO: Better UI Controls for: column visibility. Quantity selector.
return (
@@ -145,9 +145,7 @@ const ApplicationsList: FC = () => {
id={`${column.id}-view`}
checked={column.getIsVisible()}
onChange={column.getToggleVisibilityHandler()}
/>
{' '}
{column.columnDef.header?.toString() ?? column.id}
/> {column.columnDef.header?.toString() ?? column.id}
</label>
</div>
))}
@@ -161,8 +159,8 @@ const ApplicationsList: FC = () => {
<TableHeadCell
key={header.id}
className={css({
'verticalAlign': 'top',
'position': 'relative',
verticalAlign: 'top',
position: 'relative',
'&:hover > [data-is-resizing]': {
backgroundColor: 'border'
}
@@ -189,27 +187,27 @@ const ApplicationsList: FC = () => {
size="small"
onClick={header.column.getToggleSortingHandler()}
>
<FontAwesomeIcon icon={header.column.getIsSorted() === 'asc' ? faSortAsc : header.column.getIsSorted() === 'desc' ? faSortDesc : faSort} size="sm" />
<FontAwesomeIcon icon={header.column.getIsSorted() === 'asc' ? faSortAsc : header.column.getIsSorted() === 'desc' ? faSortDesc : faSort} size="sm" fixedWidth />
</IconButton>
)}
</div>
{header.column.getCanFilter()
? (
<ApplicationsFilter column={header.column} />
<ApplicationsFilter column={header.column}/>
)
: null}
: null
}
</div>
<button
type="button"
<div
className={css({
'position': 'absolute',
'top': 0,
'right': 0,
'height': '100%',
'width': '5px',
'cursor': 'col-resize',
'userSelect': 'none',
'touchAction': 'none',
position: 'absolute',
top: 0,
right: 0,
height: '100%',
width: '5px',
cursor: 'col-resize',
userSelect: 'none',
touchAction: 'none',
'&:hover': {
backgroundColor: 'border'
},
@@ -257,20 +255,14 @@ const ApplicationsList: FC = () => {
onClick={() => { table.previousPage() }}
disabled={!table.getCanPreviousPage()}
>
<FontAwesomeIcon icon={faChevronLeft} />
<FontAwesomeIcon icon={faChevronLeft} fixedWidth />
</IconButton>
Pagina
{' '}
{table.getState().pagination.pageIndex + 1}
{' '}
de
{' '}
{table.getPageCount()}
Pagina {table.getState().pagination.pageIndex + 1} de {table.getPageCount()}
<IconButton
onClick={() => { table.nextPage() }}
disabled={!table.getCanNextPage()}
>
<FontAwesomeIcon icon={faChevronRight} />
<FontAwesomeIcon icon={faChevronRight} fixedWidth />
</IconButton>
</div>
</>
@@ -15,17 +15,17 @@ const RoleSelector: FC<RoleSelectorProps> = ({ id, value, onChange, allowEmpty }
<select
id={`${id}-status`}
className={css({
'width': '100%',
'border': 'none',
'background': 'transparent',
'color': 'inherit',
'outline': 'none',
'cursor': 'pointer',
'fontSize': 'inherit',
'fontWeight': 'inherit',
'lineHeight': 'inherit',
'padding': '0',
'borderRadius': '0',
width: '100%',
border: 'none',
background: 'transparent',
color: 'inherit',
outline: 'none',
cursor: 'pointer',
fontSize: 'inherit',
fontWeight: 'inherit',
lineHeight: 'inherit',
padding: '0',
borderRadius: '0',
'&:focus': {
outline: 'none'
}
@@ -15,17 +15,17 @@ const StatusSelector: FC<StatusSelectorProps> = ({ id, value, onChange, allowEmp
<select
id={`${id}-status`}
className={css({
'width': '100%',
'border': 'none',
'background': 'transparent',
'color': 'inherit',
'outline': 'none',
'cursor': 'pointer',
'fontSize': 'inherit',
'fontWeight': 'inherit',
'lineHeight': 'inherit',
'padding': '0',
'borderRadius': '0',
width: '100%',
border: 'none',
background: 'transparent',
color: 'inherit',
outline: 'none',
cursor: 'pointer',
fontSize: 'inherit',
fontWeight: 'inherit',
lineHeight: 'inherit',
padding: '0',
borderRadius: '0',
'&:focus': {
outline: 'none'
}
+9 -6
View File
@@ -25,9 +25,9 @@ const getTeams = async (): Promise<GetTeamsResponse> => {
const moderatorMembers: Models.MembershipList = await getClanMembers(MODERATOR_CLAN_ID)
const collaboratorMembers: Models.MembershipList = await getClanMembers(COLLABORATOR_CLAN_ID)
const adminsPromises = adminMembers.memberships.map(async (membership) => await getUser(membership.userId))
const moderatorsPromises = moderatorMembers.memberships.map(async (membership) => await getUser(membership.userId))
const collaboratorsPromises = collaboratorMembers.memberships.map(async (membership) => await getUser(membership.userId))
const adminsPromises = adminMembers.memberships.map(async membership => await getUser(membership.userId))
const moderatorsPromises = moderatorMembers.memberships.map(async membership => await getUser(membership.userId))
const collaboratorsPromises = collaboratorMembers.memberships.map(async membership => await getUser(membership.userId))
const [admins, moderators, collaborators] = await Promise.all([
Promise.all(adminsPromises), Promise.all(moderatorsPromises), Promise.all(collaboratorsPromises)
@@ -96,7 +96,8 @@ const EquipoPage: FC = async () => {
<Typography variant="body2" color="info">
Ups, parece que ahora mismo no hay administradores, pero en EntGamers siempre estamos estamos buscando gente que quiera organizar cosas para la comunidad, puedes contactarnos para formar parte de nuestro equipo haciendo click en el siguiente enlace.
</Typography>
)}
)
}
<div className={center()}>
<NextLink
className={button({ color: 'info' })}
@@ -157,7 +158,8 @@ const EquipoPage: FC = async () => {
<Typography variant="body2" color="info">
Ups, parece que ahora mismo no hay moderadores, pero en EntGamers siempre estamos buscando gente que quiera ayudar a la comunidad. si quieres ser moderador, puedes hacer click en el botón de abajo.
</Typography>
)}
)
}
<div className={center()}>
<NextLink
className={button({ color: 'info' })}
@@ -218,7 +220,8 @@ const EquipoPage: FC = async () => {
<Typography variant="body2" color="info">
Ups, parece que ahora mismo no hay colaboradores, pero en EntGamers siempre estamos buscando gente que quiera ayudar a la comunidad. si quieres ser colaborador, puedes hacer click en el botón de abajo.
</Typography>
)}
)
}
<div className={center()}>
<NextLink
className={button({ color: 'info' })}
+60 -98
View File
@@ -16,14 +16,11 @@ import { ADMIN_CLAN_ID, COLLABORATOR_CLAN_ID, MODERATOR_CLAN_ID } from 'entgamer
import { createTeamApplication, type TeamApplicationData } from 'entgamers-database/frontend/database/teamApplications'
import { useFormik } from 'formik'
import { AnimatePresence, motion } from 'framer-motion'
import { usePathname, useSearchParams } from 'next/navigation'
import { useRouter } from 'next/router'
import { useSearchParams } from 'next/navigation'
import { useEffect, type FC } from 'react'
const ApplyForm: FC = () => {
const searchParams = useSearchParams()
const pathname = usePathname()
const router = useRouter()
const { manageError } = useManageError()
const dispatch = useAppDispatch()
@@ -57,11 +54,8 @@ const ApplyForm: FC = () => {
.catch((error) => {
console.error(error)
})
.finally(() => {
router.replace(pathname)
})
}
}, [searchParams, formik, pathname, router])
}, [])
return (
<form
@@ -76,7 +70,7 @@ const ApplyForm: FC = () => {
})}
>
<Button
type="button"
type='button'
onClick={() => {
formik.setFieldValue('role', MODERATOR_CLAN_ID)
.catch((error) => {
@@ -88,7 +82,7 @@ const ApplyForm: FC = () => {
Moderador
</Button>
<Button
type="button"
type='button'
onClick={() => {
formik.setFieldValue('role', ADMIN_CLAN_ID)
.catch((error) => {
@@ -100,7 +94,7 @@ const ApplyForm: FC = () => {
Administrador
</Button>
<Button
type="button"
type='button'
onClick={() => {
formik.setFieldValue('role', COLLABORATOR_CLAN_ID)
.catch((error) => {
@@ -127,87 +121,90 @@ const ApplyForm: FC = () => {
})}
>
<FormGroup>
<label htmlFor="name">Nombre</label>
<label htmlFor='name'>Nombre</label>
<Input
id="name"
type="text"
id='name'
type='text'
value={formik.values.name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
{formik.touched.name !== undefined && formik.errors.name !== undefined
? (
<Typography variant="caption" color="danger">
<Typography variant='caption' color='danger'>
{formik.errors.name}
</Typography>
)
: (
<Typography variant="caption" color="info">
<Typography variant='caption' color='info'>
Tu nombre.
</Typography>
)}
</FormGroup>
<FormGroup>
<label htmlFor="email">Email</label>
<label htmlFor='email'>Email</label>
<Input
id="email"
type="email"
id='email'
type='email'
value={formik.values.email}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
{formik.touched.email !== undefined && formik.errors.email !== undefined
? (
<Typography variant="caption" color="danger">
<Typography variant='caption' color='danger'>
{formik.errors.email}
</Typography>
)
: (
<Typography variant="caption" color="info">
<Typography variant='caption' color='info'>
Tu email, para poder contactarte.
</Typography>
)}
)
}
</FormGroup>
<FormGroup>
<label htmlFor="discord">Nombre de Discord</label>
<label htmlFor='discord'>Nombre de Discord</label>
<Input
id="discord"
type="text"
id='discord'
type='text'
value={formik.values.discord}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
{formik.touched.discord !== undefined && formik.errors.discord !== undefined
? (
<Typography variant="caption" color="danger">
<Typography variant='caption' color='danger'>
{formik.errors.discord}
</Typography>
)
: (
<Typography variant="caption" color="info">
<Typography variant='caption' color='info'>
Tu nombre de Discord, para poder contactarte.
</Typography>
)}
)
}
</FormGroup>
<FormGroup>
<label htmlFor="message">Mensaje</label>
<label htmlFor='message'>Mensaje</label>
<TextArea
id="message"
id='message'
value={formik.values.message}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
{formik.touched.message !== undefined && formik.errors.message !== undefined
? (
<Typography variant="caption" color="danger">
<Typography variant='caption' color='danger'>
{formik.errors.message}
</Typography>
)
: (
<Typography variant="caption" color="info">
<Typography variant='caption' color='info'>
¿Por que te gustaría unirte al equipo?, ¿Que te gustaría hacer?, etc.
</Typography>
)}
)
}
</FormGroup>
<div
className={css({
@@ -215,7 +212,7 @@ const ApplyForm: FC = () => {
})}
>
<Button
type="submit"
type='submit'
disabled={!formik.isValid || !formik.dirty}
fullWidth
@@ -242,13 +239,14 @@ const ApplyForm: FC = () => {
justifyContent: 'center'
})}
>
<Typography variant="h2" align="center">¡Gracias por interesarte en unirte al equipo!</Typography>
<Typography variant="body1">
<Typography variant='h2' align="center">¡Gracias por interesarte en unirte al equipo!</Typography>
<Typography variant='body1'>
El equipo de EntGamers se pondrá en contacto contigo a la brevedad posible.
</Typography>
</div>
</div>
)}
)
}
<div
className={css({
overflow: 'hidden',
@@ -256,39 +254,31 @@ const ApplyForm: FC = () => {
paddingBlock: 'medium'
})}
>
<AnimatePresence mode="wait" initial={false}>
<AnimatePresence mode='wait' initial={false}>
{formik.values.role === MODERATOR_CLAN_ID && (
<motion.div
key="motion-moderator"
key={'motion-moderator'}
transition={{ duration: 0.15, ease: 'easeInOut' }}
initial={{ opacity: 0, x: '-250px' }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: '250px' }}
>
<Typography variant="h2" align="center">Moderadores</Typography>
<Typography variant="body1">
<Typography variant='h2' align="center">Moderadores</Typography>
<Typography variant='body1'>
El equipo de moderación de EntGamers se encarga de moderar los distintos espacios en los que se desenvuelve la comunidad, como los grupos de Facebook, Discord, Etc.
</Typography>
<Typography variant="h3">Requisitos</Typography>
<Typography variant='h3'>Requisitos</Typography>
<ul className="fa-ul">
<li>
<span className="fa-li">
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
</span>
{' '}
<strong>Imparcialidad</strong>
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Imparcialidad</strong>
<br />
La comunidad esta conformada por amigos y conocidos, por lo tanto es importante poder actuar de forma imparcial y responsable.
</li>
</ul>
<Typography variant="h3">Beneficios</Typography>
<Typography variant='h3'>Beneficios</Typography>
<ul className="fa-ul">
<li>
<span className="fa-li">
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
</span>
{' '}
<strong>Experiencia</strong>
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Experiencia</strong>
<br />
Uno de los objetivos de la comunidad es brindar experiencia en gestión y desarrollo de proyectos equiparable a un entorno laboral, que sea comprobable y útil.
</li>
@@ -297,36 +287,28 @@ const ApplyForm: FC = () => {
)}
{formik.values.role === COLLABORATOR_CLAN_ID && (
<motion.div
key="motion-collaborator"
key={'motion-collaborator'}
transition={{ duration: 0.15, ease: 'easeInOut' }}
initial={{ opacity: 0, x: '-250px' }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: '250px' }}
>
<Typography variant="h2" align="center">Colaborador</Typography>
<Typography variant="body1">
<Typography variant='h2' align='center'>Colaborador</Typography>
<Typography variant='body1'>
Los colaboradores son personas ajenas al staff central de EntGamers que nos ayudan a traer contenido, eventos y actividades a la comunidad.
</Typography>
<Typography variant="h3">Requisitos</Typography>
<Typography variant='h3'>Requisitos</Typography>
<ul className="fa-ul">
<li>
<span className="fa-li">
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
</span>
{' '}
<strong>Profesionalismo</strong>
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Profesionalismo</strong>
<br />
La comunidad siempre intenta conseguir el mayor nivel de calidad en todos sus proyectos, por lo que buscamos gente dispuesta a otorgar este nivel de profesionalismo para el disfrute de la comunidad.
</li>
</ul>
<Typography variant="h3">Beneficios</Typography>
<Typography variant='h3'>Beneficios</Typography>
<ul className="fa-ul">
<li>
<span className="fa-li">
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
</span>
{' '}
<strong>Apoyo</strong>
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Apoyo</strong>
<br />
Puedes contar con el apoyo de la comunidad para tus proyectos, ya sea en forma de difusión, asesoramiento o recursos.
</li>
@@ -335,63 +317,43 @@ const ApplyForm: FC = () => {
)}
{formik.values.role === ADMIN_CLAN_ID && (
<motion.div
key="motion-administrator"
key={'motion-administrator'}
transition={{ duration: 0.15, ease: 'easeInOut' }}
initial={{ opacity: 0, x: '-250px' }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: '250px' }}
>
<Typography variant="h2" align="center">Administradores</Typography>
<Typography variant="body1">
<Typography variant='h2' align='center'>Administradores</Typography>
<Typography variant='body1'>
Los administradores son quienes se encargan de que todo funcione como es debido en la comunidad, desde la moderación de los grupos hasta la organización de eventos y actividades. Son los responsables de que la comunidad siga creciendo y mejorando.
</Typography>
<Typography variant="h3">Requisitos</Typography>
<Typography variant='h3'>Requisitos</Typography>
<ul className="fa-ul">
<li>
<span className="fa-li">
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
</span>
{' '}
<strong>Profesionalismo</strong>
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Profesionalismo</strong>
<br />
La comunidad siempre intenta conseguir el mayor nivel de calidad en todos sus proyectos, por lo que buscamos gente dispuesta a otorgar este nivel de profesionalismo para el disfrute de la comunidad.
</li>
<li>
<span className="fa-li">
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
</span>
{' '}
<strong>Constancia</strong>
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Constancia</strong>
<br />
La comunidad busca gente que en sus posibilidades sea activa, que pueda estar al tanto de lo que pasa en ella.
</li>
<li>
<span className="fa-li">
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
</span>
{' '}
<strong>Proactividad</strong>
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Proactividad</strong>
<br />
La comunidad esta en constante crecimiento, por eso, buscamos gente que ayude a buscar nuevas oportunidades para diferentes proyectos y actividades de interés a la comunidad.
</li>
</ul>
<Typography variant="h3">Beneficios</Typography>
<Typography variant='h3'>Beneficios</Typography>
<ul className="fa-ul">
<li>
<span className="fa-li">
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
</span>
{' '}
<strong>Experiencia</strong>
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Experiencia</strong>
<br />
Uno de los objetivos de la comunidad es brindar experiencia en gestión y desarrollo de proyectos equiparable a un entorno laboral, que sea comprobable y útil.
</li>
<li>
<span className="fa-li">
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
</span>
{' '}
<strong>Capacitación</strong>
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Capacitación</strong>
<br />
La comunidad buscara dar capacitación a sus miembros en lo referido a herramientas y procedimientos utilizados.
</li>
+1 -3
View File
@@ -1,7 +1,7 @@
import Typography from '@/components/ui/Typography'
import { Container } from '@/styled-system/jsx'
import { ensureTeamApplicationsCollection } from 'entgamers-database/backend/database/teamApplications'
import { Suspense, type FC } from 'react'
import { type FC } from 'react'
import ApplyForm from './ApplyForm'
const EquipoUnirsePage: FC = async () => {
@@ -12,9 +12,7 @@ const EquipoUnirsePage: FC = async () => {
<Typography variant="body1">
El equipo de EntGamers está formado por personas que se dedican a la administración de la comunidad, a la organización de eventos y a la creación de contenido. Aquí podrás enterarte cuales son las funciones de cada uno de los miembros del equipo y como puedes unirte a nosotros.
</Typography>
<Suspense fallback={<Typography variant="body1">Cargando...</Typography>}>
<ApplyForm />
</Suspense>
</Container>
)
}
+2 -2
View File
@@ -8,8 +8,8 @@ import '@fontsource/open-sans/latin-700.css'
import '@fontsource/permanent-marker/latin-400.css'
import { config } from '@fortawesome/fontawesome-svg-core'
import '@fortawesome/fontawesome-svg-core/styles.css'
import type { Metadata } from 'next'
import type { FC, ReactNode } from 'react'
import { type Metadata } from 'next'
import { type FC, type ReactNode } from 'react'
import FeedbackConsumer from './FeedbackConsumer'
import SessionConsumer from './SessionConsumer'
import StateProvider from './StateProvider'
+2 -4
View File
@@ -57,7 +57,7 @@ const LoginForm: FC = () => {
if (session.status === 'idle' && session.session !== undefined) {
router.push('/')
}
}, [session, router])
}, [session])
return (
<form
@@ -95,9 +95,7 @@ const LoginForm: FC = () => {
)}
</FormGroup>
<Typography variant="caption" color="muted">
¿Perdiste tu contraseña?
{' '}
<NextLink href="/recover-password">Recupérala</NextLink>
¿Perdiste tu contraseña? <NextLink href="/recover-password">Recupérala</NextLink>
</Typography>
<FormGroup>
<Button
+4 -5
View File
@@ -15,7 +15,8 @@ const LoginPage: FC = () => {
container(),
css({
minHeight: 'calc(100vh - 60px - 72px)'
}))}
}))
}
>
<div
className={cx(
@@ -40,10 +41,8 @@ const LoginPage: FC = () => {
className={card().content}
>
<LoginForm />
<Typography variant="caption" align="center">
¿No tienes una cuenta?
{' '}
<NextLink href="/register">Regístrate</NextLink>
<Typography variant="caption" align="center" >
¿No tienes una cuenta? <NextLink href="/register">Regístrate</NextLink>
</Typography>
</div>
</div>
@@ -68,11 +68,10 @@ const CreateRecoverPasswordForm: FC = () => {
{formik.errors.email}
</Typography>
)
: (
<Typography variant="caption" color="info">
: (<Typography variant="caption" color="info">
Por favor, introduce el correo electrónico con el que te has registrado. Te enviaremos un correo con instrucciones para la recuperación de contraseña
</Typography>
)}
</Typography>)
}
</FormGroup>
<FormGroup>
<Button
@@ -1,23 +1,27 @@
'use client'
import CreateRecoverPasswordForm from '@/app/recover-password/CreateRecoverPasswordForm'
import { useSearchParams } from 'next/navigation'
import type { FC } from 'react'
import { useEffect, useState, type FC } from 'react'
import UpdateRecoverPasswordForm, { type UpdateRecoverPasswordFormProps } from './UpdateRecoverPasswordForm'
const ManageRecoverPassword: FC = () => {
const [recoverData, setRecoverData] = useState<UpdateRecoverPasswordFormProps | undefined>()
const searchParams = useSearchParams()
useEffect(() => {
const userId = searchParams.get('userId')
const secret = searchParams.get('secret')
const recoverData: UpdateRecoverPasswordFormProps | undefined = (userId !== null && secret !== null) ? { userId, secret } : undefined
if (userId !== null && secret !== null) {
setRecoverData({ userId, secret })
}
}, [])
if (recoverData === undefined) {
return <CreateRecoverPasswordForm />
} else {
return (
<UpdateRecoverPasswordForm
return <UpdateRecoverPasswordForm
{...recoverData}
/>
)
}
}
@@ -89,7 +89,8 @@ const UpdateRecoverPasswordForm: FC<UpdateRecoverPasswordFormProps> = (props) =>
<Typography variant="caption" color="info">
Escribe tu nueva contraseña
</Typography>
)}
)
}
</FormGroup>
<FormGroup>
<label htmlFor="confirmPassword">
+3 -4
View File
@@ -4,7 +4,7 @@ import { css, cx } from '@/styled-system/css'
import { Center } from '@/styled-system/jsx'
import { container } from '@/styled-system/patterns'
import { card } from '@/styled-system/recipes'
import { Suspense, type FC } from 'react'
import { type FC } from 'react'
const page: FC = () => {
return (
@@ -13,7 +13,8 @@ const page: FC = () => {
container(),
css({
minHeight: 'calc(100vh - 60px - 72px)'
}))}
}))
}
>
<div
className={cx(
@@ -35,9 +36,7 @@ const page: FC = () => {
<div
className={card().content}
>
<Suspense fallback={<Typography variant="body1">Cargando...</Typography>}>
<ManageRecoverPassword />
</Suspense>
</div>
</div>
</Center>
+4 -5
View File
@@ -15,7 +15,8 @@ const RegisterPage: FC = () => {
container(),
css({
minHeight: 'calc(100vh - 60px - 72px)'
}))}
}))
}
>
<div
@@ -41,10 +42,8 @@ const RegisterPage: FC = () => {
className={card().content}
>
<RegisterForm />
<Typography variant="caption" align="center">
¿Ya tienes una cuenta?
{' '}
<NextLink href="/login">Inicia sesión</NextLink>
<Typography variant="caption" align="center" >
¿Ya tienes una cuenta? <NextLink href="/login">Inicia sesión</NextLink>
</Typography>
</div>
</div>
+7 -23
View File
@@ -4,7 +4,7 @@ import { Container } from '@/styled-system/jsx'
import { faChevronRight, faHeart } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import NextLink from 'next/link'
import type { FC } from 'react'
import { type FC } from 'react'
const Footer: FC = () => {
return (
@@ -22,24 +22,14 @@ const Footer: FC = () => {
})}
>
<div>
<Typography variant="h3" component="div"> Acerca de </Typography>
<Typography variant="h3" component='div'> Acerca de </Typography>
<ul className="fa-ul">
<li>
<span className="fa-li">
<FontAwesomeIcon icon={faChevronRight} />
</span>
<NextLink href="/acerca-de"> EntGamers</NextLink>
</li>
<li>
<span className="fa-li">
<FontAwesomeIcon icon={faChevronRight} />
</span>
<NextLink href="/clanes"> Clanes</NextLink>
</li>
<li><FontAwesomeIcon icon={faChevronRight} listItem fixedWidth /><NextLink href="/acerca-de"> EntGamers</NextLink></li>
<li><FontAwesomeIcon icon={faChevronRight} listItem fixedWidth /><NextLink href="/clanes"> Clanes</NextLink></li>
</ul>
</div>
<div>
<Typography variant="h3" component="div"> Contacto </Typography>
<Typography variant="h3" component='div'> Contacto </Typography>
</div>
<div></div>
</Container>
@@ -50,14 +40,8 @@ const Footer: FC = () => {
justifyContent: 'center'
})}
>
<Typography variant="body2" component="div">
Hecho con
{' '}
<FontAwesomeIcon className={css({ color: 'red' })} icon={faHeart} />
{' '}
por
{' '}
<a href="https://srjuggernaut.dev">SrJuggernaut</a>
<Typography variant="body2" component='div'>
Hecho con <FontAwesomeIcon className={css({ color: 'red' })} icon={faHeart} /> por <a href="https://srjuggernaut.dev">SrJuggernaut</a>
</Typography>
</Container>
</footer>
+17 -17
View File
@@ -21,28 +21,28 @@ const Header: FC = () => {
return () => {
window.removeEventListener('scroll', handleScroll)
}
}, [handleScroll])
}, [])
return (
<>
<header
className={css({
'display': 'flex',
'alignItems': 'center',
'justifyContent': 'center',
'backgroundColor': 'transparent',
'color': 'text',
'minHeight': '60px',
'position': 'fixed',
'top': 0,
'left': 0,
'width': '100%',
'zIndex': 'sticky',
'boxShadow': 'none',
'transitionProperty': 'background-color, box-shadow',
'transitionDuration': '0.25s',
'transitionTimingFunction': 'easeInOut',
'willChange': 'background-color, box-shadow',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'transparent',
color: 'text',
minHeight: '60px',
position: 'fixed',
top: 0,
left: 0,
width: '100%',
zIndex: 'sticky',
boxShadow: 'none',
transitionProperty: 'background-color, box-shadow',
transitionDuration: '0.25s',
transitionTimingFunction: 'easeInOut',
willChange: 'background-color, box-shadow',
'&[data-scrolled=true]': {
backgroundColor: 'surface',
boxShadow: '2px 2px 4px 0px rgba(0, 0, 0, 0.25)'
+17 -15
View File
@@ -11,10 +11,10 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { ADMIN_CLAN_ID, MODERATOR_CLAN_ID } from 'entgamers-database/frontend/clanes/administrative'
import { logout } from 'entgamers-database/frontend/session'
import NextLink from 'next/link'
import type { FC } from 'react'
import { type FC } from 'react'
const SessionButtons: FC = () => {
const { session, status, clanes } = useAppSelector((state) => state.session)
const { session, status, clanes } = useAppSelector(state => state.session)
const { manageError } = useManageError()
const dispatch = useAppDispatch()
@@ -22,9 +22,10 @@ const SessionButtons: FC = () => {
if (status === 'idle' && session === undefined) {
return (
<>
<Tooltip
title="Iniciar sesión"
position="bottom"
title={'Iniciar sesión'}
position='bottom'
>
<NextLink
href="/login"
@@ -32,9 +33,10 @@ const SessionButtons: FC = () => {
iconButton()
}
>
<FontAwesomeIcon icon={faUser} />
<FontAwesomeIcon icon={faUser} fixedWidth />
</NextLink>
</Tooltip>
</>
)
}
@@ -42,8 +44,8 @@ const SessionButtons: FC = () => {
return (
<>
<Tooltip
title="Mi cuenta"
position="bottom"
title={'Mi cuenta'}
position='bottom'
>
<NextLink
href="/cuenta"
@@ -51,13 +53,13 @@ const SessionButtons: FC = () => {
iconButton()
}
>
<FontAwesomeIcon icon={faUser} />
<FontAwesomeIcon icon={faUser} fixedWidth />
</NextLink>
</Tooltip>
{clanes?.teams.some((team) => team.$id === ADMIN_CLAN_ID || team.$id === MODERATOR_CLAN_ID) && (
{clanes !== undefined && clanes?.teams.some(team => team.$id === ADMIN_CLAN_ID || team.$id === MODERATOR_CLAN_ID) && (
<Tooltip
title="Panel de administración"
position="bottom"
title={'Panel de administración'}
position='bottom'
>
<NextLink
href="/dashboard"
@@ -65,13 +67,13 @@ const SessionButtons: FC = () => {
iconButton()
}
>
<FontAwesomeIcon icon={faCogs} />
<FontAwesomeIcon icon={faCogs} fixedWidth />
</NextLink>
</Tooltip>
)}
<Tooltip
title="Cerrar sesión"
position="bottom"
title={'Cerrar sesión'}
position='bottom'
>
<IconButton
onClick={() => {
@@ -89,7 +91,7 @@ const SessionButtons: FC = () => {
})
}}
>
<FontAwesomeIcon icon={faRightFromBracket} />
<FontAwesomeIcon icon={faRightFromBracket} fixedWidth />
</IconButton>
</Tooltip>
</>
+15 -18
View File
@@ -3,7 +3,7 @@ import BackDrop from '@/components/ui/BackDrop'
import IconButton from '@/components/ui/IconButton'
import { css } from '@/styled-system/css'
import { iconButton } from '@/styled-system/recipes'
import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
import { type IconDefinition } from '@fortawesome/fontawesome-common-types'
import { faBars, faHome, faTimes, faUsers } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import NextLink from 'next/link'
@@ -62,7 +62,6 @@ const Menu: FC = () => {
})}
>
<button
type="button"
className={iconButton({
color: 'danger'
})}
@@ -81,21 +80,22 @@ const Menu: FC = () => {
>
{menuLinks.map((menuLink, index) => (
<li
key={`menu-link-${menuLink.label}-${index.toString()}`}
key={`menu-link-${index}`}
onClick={() => { setIsMenuOpen(false) }}
>
<NextLink
className={css({
'display': 'flex',
'alignItems': 'center',
'justifyContent': 'left',
'padding': '1rem',
'textDecoration': 'none',
'backgroundColor': 'transparent',
'color': 'text',
'transitionProperty': 'background-color',
'transitionDuration': 'normal',
'transitionTimingFunction': 'easeInOut',
'willChange': 'background-color color',
display: 'flex',
alignItems: 'center',
justifyContent: 'left',
padding: '1rem',
textDecoration: 'none',
backgroundColor: 'transparent',
color: 'text',
transitionProperty: 'background-color',
transitionDuration: 'normal',
transitionTimingFunction: 'easeInOut',
willChange: 'background-color color',
'&:hover': {
backgroundColor: 'primary',
color: 'primary.contrast'
@@ -107,11 +107,8 @@ const Menu: FC = () => {
})}
href={menuLink.href}
data-active={pathName === menuLink.href}
onClick={() => { setIsMenuOpen(false) }}
>
<FontAwesomeIcon icon={menuLink.icon} />
&nbsp;
{menuLink.label}
<FontAwesomeIcon icon={menuLink.icon} fixedWidth />&nbsp;{menuLink.label}
</NextLink>
</li>
))}
+5 -4
View File
@@ -1,9 +1,9 @@
import { cx } from '@/styled-system/css'
import { alert, type AlertVariantProps } from '@/styled-system/recipes/alert'
import type { MergeOmitting } from '@/types/utilities'
import { type MergeOmitting } from '@/types/utilities'
import { faTimes } from '@fortawesome/free-solid-svg-icons/faTimes'
import { FontAwesomeIcon, type FontAwesomeIconProps } from '@fortawesome/react-fontawesome'
import type { DetailedHTMLProps, FC, HTMLAttributes, ReactNode } from 'react'
import { type DetailedHTMLProps, type FC, type HTMLAttributes, type ReactNode } from 'react'
import IconButton, { type IconButtonProps } from './IconButton'
type ComposedAlertProps = MergeOmitting<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, AlertVariantProps>
@@ -32,8 +32,9 @@ export const AlertCloseButton: FC<ComposedAlertCloseButtonProps> = ({ children,
{...allOtherAlertProps}
>
{children === undefined
? <FontAwesomeIcon icon={faTimes as FontAwesomeIconProps['icon']} size="sm" />
: children}
? <FontAwesomeIcon icon={faTimes as FontAwesomeIconProps['icon']} fixedWidth size='sm' />
: children
}
</IconButton>
)
}
+2 -1
View File
@@ -38,7 +38,8 @@ const BackDrop: FC<BackDropProps> = ({ isOpen, onClickAway, children }) => {
{children}
</motion.div>
)
: undefined}
: undefined
}
</AnimatePresence>
), document.body)
}
+5 -3
View File
@@ -1,9 +1,11 @@
import { cx } from '@/styled-system/css'
import { button, type ButtonVariantProps } from '@/styled-system/recipes/button'
import type { MergeOmitting } from '@/types/utilities'
import type { ButtonHTMLAttributes, DetailedHTMLProps, FC } from 'react'
import { type MergeOmitting } from '@/types/utilities'
import { type ButtonHTMLAttributes, type DetailedHTMLProps, type FC } from 'react'
export type ButtonProps = MergeOmitting<DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, ButtonVariantProps>
type ComposedButtonProps = MergeOmitting<DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, ButtonVariantProps>
export interface ButtonProps extends ComposedButtonProps {}
const Button: FC<ButtonProps> = ({ children, className, ...rest }) => {
const [buttonRecipeArgs, allOtherButtonProps] = button.splitVariantProps(rest)
+5 -3
View File
@@ -1,9 +1,11 @@
import { cx } from '@/styled-system/css'
import { iconButton, type IconButtonVariantProps } from '@/styled-system/recipes/icon-button'
import type { MergeOmitting } from '@/types/utilities'
import type { ButtonHTMLAttributes, DetailedHTMLProps, FC } from 'react'
import { type MergeOmitting } from '@/types/utilities'
import { type ButtonHTMLAttributes, type DetailedHTMLProps, type FC } from 'react'
export type IconButtonProps = MergeOmitting<DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, IconButtonVariantProps>
type ComposedIconButtonProps = MergeOmitting<DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, IconButtonVariantProps>
export interface IconButtonProps extends ComposedIconButtonProps {}
const IconButton: FC<IconButtonProps> = ({ children, className, ...rest }) => {
const [iconButtonRecipeArgs, allOtherIconButtonProps] = iconButton.splitVariantProps(rest)
+10 -9
View File
@@ -1,7 +1,7 @@
import { cx } from '@/styled-system/css'
import { typography, type TypographyVariantProps } from '@/styled-system/recipes/typography'
import type { MergeOmitting } from '@/types/utilities'
import { type ElementType, type FC, type HTMLAttributes, createElement } from 'react'
import { type MergeOmitting } from '@/types/utilities'
import { type ElementType, type FC, type HTMLAttributes } from 'react'
type ComposedTypographyProps = MergeOmitting<HTMLAttributes<HTMLElement>, TypographyVariantProps>
@@ -35,18 +35,19 @@ const variantToComponent = (variant: TypographyVariantProps['variant']): Element
const Typography: FC<TypographyProps> = ({ children, className, component, ...rest }) => {
const [typographyRecipeArgs, allOtherTypographyProps] = typography.splitVariantProps(rest)
const Component = component ?? variantToComponent(typographyRecipeArgs.variant)
typographyRecipeArgs.color = typographyRecipeArgs.color ?? (
typeof typographyRecipeArgs.variant === 'string' && typographyRecipeArgs.variant.startsWith('h')
? 'primary'
: 'inherit'
)
return createElement(
component ?? variantToComponent(typographyRecipeArgs.variant),
{
className: cx(typography(typographyRecipeArgs), className),
...allOtherTypographyProps
},
children
return (
<Component
className={cx(typography(typographyRecipeArgs), className)}
{...allOtherTypographyProps}
>
{children}
</Component>
)
}
+3 -5
View File
@@ -19,16 +19,14 @@ const DebouncedInput: FC<DebouncedInputProps> = ({ value: initialValue, onChange
onChange(value)
}, debounce)
return () => {
clearTimeout(timeout)
}
}, [value, onChange, debounce])
return () => { clearTimeout(timeout) }
}, [value])
return (
<Input
{...props}
value={value}
onChange={(e) => { setValue(e.target.value) }}
onChange={e => { setValue(e.target.value) }}
/>
)
}
+9 -5
View File
@@ -1,17 +1,21 @@
import { cx } from '@/styled-system/css'
import { input, type InputVariantProps } from '@/styled-system/recipes/input'
import type { MergeOmitting } from '@/types/utilities'
import type { DetailedHTMLProps, FC, InputHTMLAttributes } from 'react'
import { type MergeOmitting } from '@/types/utilities'
import { type DetailedHTMLProps, type FC, type InputHTMLAttributes } from 'react'
export type InputProps = MergeOmitting<DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, InputVariantProps>
type ComposedInputProps = MergeOmitting<DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, InputVariantProps>
const Input: FC<InputProps> = ({ className, ...rest }) => {
export interface InputProps extends ComposedInputProps {}
const Input: FC<InputProps> = ({ children, className, ...rest }) => {
const [inputRecipeArgs, allOtherInputProps] = input.splitVariantProps(rest)
return (
<input
className={cx(input(inputRecipeArgs), className)}
{...allOtherInputProps}
/>
>
{children}
</input>
)
}
+2 -2
View File
@@ -2,7 +2,7 @@ import IconButton from '@/components/ui/IconButton'
import Tooltip from '@/components/ui/Tooltip'
import { css, cx } from '@/styled-system/css'
import { input, type InputVariantProps } from '@/styled-system/recipes/input'
import type { MergeOmitting } from '@/types/utilities'
import { type MergeOmitting } from '@/types/utilities'
import { faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { useState, type FC, type InputHTMLAttributes } from 'react'
@@ -47,7 +47,7 @@ const PasswordInput: FC<InputProps> = ({ className, ...props }) => {
size="small"
onClick={() => { setShowPassword(!showPassword) }}
>
<FontAwesomeIcon icon={showPassword ? faEyeSlash : faEye} />
<FontAwesomeIcon icon={showPassword ? faEyeSlash : faEye} fixedWidth/>
</IconButton>
</Tooltip>
</div>
+3 -3
View File
@@ -13,16 +13,16 @@ const feedbackSlice = createSlice({
name: 'feedback',
initialState,
reducers: {
addAlert(state, action: PayloadAction<Alert>) {
addAlert (state, action: PayloadAction<Alert>) {
return {
...state,
alerts: [...state.alerts, action.payload]
}
},
removeAlert(state, action: PayloadAction<string>) {
removeAlert (state, action: PayloadAction<string>) {
return {
...state,
alerts: state.alerts.filter((alert) => alert.id !== action.payload)
alerts: state.alerts.filter(alert => alert.id !== action.payload)
}
}
}
+6 -6
View File
@@ -1,15 +1,15 @@
import { createSlice, type PayloadAction } from '@reduxjs/toolkit'
import type { Models } from 'appwrite'
import type { ClanList } from 'entgamers-database/frontend/clanes'
import type { User } from 'entgamers-database/frontend/session'
import { type Models } from 'appwrite'
import { type ClanList } from 'entgamers-database/frontend/clanes'
import { type User } from 'entgamers-database/frontend/session'
export type SessionState
= | {
export type SessionState =
| {
status: 'idle' | 'loading' | 'initializing'
session?: Models.Session
user?: User
clanes?: ClanList
}
}
const initialState: SessionState = {
status: 'initializing'
+4 -5
View File
@@ -12,11 +12,11 @@
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"module": "Node16",
"moduleResolution": "Node16",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"jsx": "preserve",
"incremental": true,
"baseUrl": "src",
"paths": {
@@ -35,8 +35,7 @@
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
"next.config.js",
".next/dev/types/**/*.ts"
"next.config.js"
],
"exclude": [
"node_modules"