Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e03c43ded | |||
| c979e6540f | |||
| 7a87eac395 | |||
| ff0d24bbb6 | |||
| ddeed0a6ef | |||
| e105edbbee | |||
| 9878ca7f1c | |||
| 7d5c0aeea9 | |||
| 7f758d9d0b | |||
| 820865ac79 | |||
| 345f79e53a | |||
| 9403b28040 | |||
| c21617aec3 | |||
| 7696c4f371 | |||
| 84f02c9bc5 | |||
| 0042cbee31 | |||
| 71c14fee52 | |||
| 21bd696a30 | |||
| 5f9b972983 | |||
| 57f5f80969 | |||
| 984799d502 | |||
| 8d8b5e1646 | |||
| 4f37fd4734 | |||
| b7e273ae06 | |||
| ab82d0797d | |||
| 8c95537324 | |||
| a6e072703d | |||
| 7d39bb3d89 | |||
| 0c74c0a0a9 | |||
| b393e0cdb0 | |||
| ba466dfd80 | |||
| ee8bf42aad | |||
| b2756b0654 | |||
| b01e211acb | |||
| 33a3e7bb70 | |||
| a8c579b94e | |||
| bde70454dc | |||
| 2135a4b55d | |||
| eb334f6357 |
-134
@@ -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
@@ -1,3 +1,7 @@
|
|||||||
|
# App variables
|
||||||
|
|
||||||
|
SITE_NAME="EntGamers"
|
||||||
|
|
||||||
# Deployment variables
|
# Deployment variables
|
||||||
|
|
||||||
APP_NAME=""
|
APP_NAME=""
|
||||||
@@ -19,6 +23,5 @@ APPWRITE_API_KEY=""
|
|||||||
|
|
||||||
# Website Variables
|
# Website Variables
|
||||||
|
|
||||||
SITE_NAME="EntGamers"
|
|
||||||
NEXT_PUBLIC_SITE_URL="https://entgamers.com"
|
NEXT_PUBLIC_SITE_URL="https://entgamers.com"
|
||||||
IMAGE_DOMAINS="https://domain.com,http://another.domain.com/route/"
|
IMAGE_DOMAINS="https://domain.com,http://another.domain.com/route/"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
src/styled-system
|
||||||
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
@@ -1 +1,4 @@
|
|||||||
bunx --no -- commitlint --edit "${1}"
|
#!/bin/sh
|
||||||
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
npx --no -- commitlint --edit "${1}"
|
||||||
|
|||||||
@@ -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 +0,0 @@
|
|||||||
bunx lint-staged --config lint-staged.config.ts
|
|
||||||
Executable
+4
@@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
. "$(dirname -- "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
npm run lint
|
||||||
-52
@@ -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"]
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
module.exports = { extends: ['@commitlint/config-conventional'] }
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import type { UserConfig } from '@commitlint/types'
|
|
||||||
|
|
||||||
const Configuration: UserConfig = { extends: ['@commitlint/config-conventional'] }
|
|
||||||
|
|
||||||
export default Configuration
|
|
||||||
+18
-31
@@ -2,55 +2,42 @@ module.exports = {
|
|||||||
apps: [
|
apps: [
|
||||||
{
|
{
|
||||||
name: process.env.APP_NAME || 'entgamers-website',
|
name: process.env.APP_NAME || 'entgamers-website',
|
||||||
script: 'bun',
|
script: 'yarn',
|
||||||
args: 'run start',
|
args: 'run start',
|
||||||
env: {
|
env: {
|
||||||
NODE_ENV: 'production',
|
NODE_ENV: 'production',
|
||||||
PORT: process.env.PORT || 3000,
|
PORT: process.env.PORT || 3000,
|
||||||
NEXT_PUBLIC_APPWRITE_ENDPOINT: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT,
|
DISCORD_JOIN_WEBHOOK_URL: process.env.DISCORD_JOIN_WEBHOOK_URL
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
deploy: {
|
deploy: {
|
||||||
production: {
|
production: {
|
||||||
'user': process.env.SSH_USERNAME,
|
user: process.env.SSH_USERNAME,
|
||||||
'host': process.env.DEPLOY_HOST,
|
host: process.env.DEPLOY_HOST,
|
||||||
'ref': 'origin/production',
|
ref: 'origin/production',
|
||||||
'repo': 'https://github.com/SrJuggernaut/entgamers_pro',
|
repo: 'https://github.com/SrJuggernaut/entgamers_pro',
|
||||||
'path': process.env.DEPLOY_PATH,
|
path: process.env.DEPLOY_PATH,
|
||||||
'post-deploy': 'pm2 --silent startOrRestart ecosystem.config.js',
|
'post-deploy': 'pm2 --silent startOrRestart ecosystem.config.js',
|
||||||
'env': {
|
env: {
|
||||||
|
APP_NAME: process.env.APP_NAME,
|
||||||
PORT: process.env.PORT,
|
PORT: process.env.PORT,
|
||||||
NEXT_PUBLIC_APPWRITE_ENDPOINT: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT,
|
DISCORD_JOIN_WEBHOOK_URL: process.env.DISCORD_JOIN_WEBHOOK_URL
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
preview: {
|
preview: {
|
||||||
'user': process.env.SSH_USERNAME,
|
user: process.env.SSH_USERNAME,
|
||||||
'host': process.env.DEPLOY_HOST,
|
host: process.env.DEPLOY_HOST,
|
||||||
'ref': 'origin/preview',
|
ref: 'origin/preview',
|
||||||
'repo': 'https://github.com/SrJuggernaut/entgamers_pro',
|
repo: 'https://github.com/SrJuggernaut/entgamers_pro',
|
||||||
'path': process.env.DEPLOY_PATH,
|
path: process.env.DEPLOY_PATH,
|
||||||
'post-deploy': 'pm2 --silent startOrRestart ecosystem.config.js',
|
'post-deploy': 'pm2 --silent startOrRestart ecosystem.config.js',
|
||||||
'env': {
|
env: {
|
||||||
|
APP_NAME: process.env.APP_NAME,
|
||||||
PORT: process.env.PORT,
|
PORT: process.env.PORT,
|
||||||
NEXT_PUBLIC_APPWRITE_ENDPOINT: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT,
|
DISCORD_JOIN_WEBHOOK_URL: process.env.DISCORD_JOIN_WEBHOOK_URL
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
])
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import type { Configuration } from 'lint-staged'
|
|
||||||
|
|
||||||
const config: Configuration = {
|
|
||||||
'*.{js,jsx,ts,tsx}': 'eslint --fix'
|
|
||||||
}
|
|
||||||
|
|
||||||
export default config
|
|
||||||
Vendored
+1
-2
@@ -1,6 +1,5 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
import "./.next/types/routes.d.ts";
|
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// 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.
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
@@ -5,51 +5,56 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"develop": "next dev",
|
"develop": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
|
"prestart": "bun install && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "eslint .",
|
"lint": "next lint",
|
||||||
"prepare": "panda codegen && bun ./.husky/install.mts"
|
"prepare": "panda codegen && husky install"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/open-sans": "^5.0.20",
|
"@fontsource/open-sans": "^5.0.20",
|
||||||
"@fontsource/permanent-marker": "^5.0.8",
|
"@fontsource/permanent-marker": "^5.0.8",
|
||||||
"@fortawesome/fontawesome-svg-core": "^7.2.0",
|
"@fortawesome/fontawesome-svg-core": "^6.5.1",
|
||||||
"@fortawesome/free-brands-svg-icons": "^7.2.0",
|
"@fortawesome/free-brands-svg-icons": "^6.5.1",
|
||||||
"@fortawesome/free-solid-svg-icons": "^7.2.0",
|
"@fortawesome/free-solid-svg-icons": "^6.5.1",
|
||||||
"@fortawesome/react-fontawesome": "^3.3.0",
|
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||||
"@reduxjs/toolkit": "^2.0.1",
|
"@reduxjs/toolkit": "^2.0.1",
|
||||||
"@stylistic/eslint-plugin": "^5.10.0",
|
|
||||||
"@tanstack/match-sorter-utils": "^8.11.8",
|
"@tanstack/match-sorter-utils": "^8.11.8",
|
||||||
"@tanstack/react-table": "^8.19.3",
|
"@tanstack/react-table": "^8.19.3",
|
||||||
"appwrite": "^13.0.1",
|
"appwrite": "^13.0.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^3.3.1",
|
||||||
"entgamers-database": "0.0.26",
|
"entgamers-database": "0.0.26",
|
||||||
"entgamers-panda-preset": "0.1.5",
|
"entgamers-panda-preset": "0.1.5",
|
||||||
"formik": "^2.4.5",
|
"formik": "^2.4.5",
|
||||||
"framer-motion": "^12.38.0",
|
"framer-motion": "^10.17.6",
|
||||||
"isomorphic-fetch": "^3.0.0",
|
"isomorphic-fetch": "^3.0.0",
|
||||||
"lint-staged": "^16.4.0",
|
"next": "^14.0.4",
|
||||||
"next": "16.2.2",
|
|
||||||
"node-appwrite": "^11.1.0",
|
"node-appwrite": "^11.1.0",
|
||||||
"react": "19.2.4",
|
"react": "18.2.0",
|
||||||
"react-dom": "19.2.4",
|
"react-dom": "18.2.0",
|
||||||
"react-redux": "^9.0.4",
|
"react-redux": "^9.0.4",
|
||||||
"sharp": "^0.34.5",
|
"sharp": "^0.33.1",
|
||||||
"yup": "^1.3.3"
|
"yup": "^1.3.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^20.5.0",
|
"@commitlint/cli": "^18.4.4",
|
||||||
"@commitlint/config-conventional": "^20.5.0",
|
"@commitlint/config-conventional": "^18.4.4",
|
||||||
"@eslint/js": "^10.0.1",
|
"@pandacss/dev": "^0.23.0",
|
||||||
"@pandacss/dev": "^1.9.1",
|
|
||||||
"@types/bun": "^1.3.11",
|
|
||||||
"@types/isomorphic-fetch": "^0.0.39",
|
"@types/isomorphic-fetch": "^0.0.39",
|
||||||
"@types/react": "19.2.14",
|
"@types/node": "^20.10.6",
|
||||||
"@types/react-dom": "19.2.3",
|
"@types/react": "^18.2.46",
|
||||||
"eslint": "^10.1.0",
|
"@types/react-dom": "^18.2.18",
|
||||||
"eslint-config-next": "16.2.2",
|
"@typescript-eslint/eslint-plugin": "^6.4.0",
|
||||||
"eslint-plugin-react": "^7.37.5",
|
"@typescript-eslint/parser": "^5.38.0",
|
||||||
"husky": "^9.1.7",
|
"eslint": "^8.0.1",
|
||||||
"typescript": "*",
|
"eslint-config-next": "latest",
|
||||||
"typescript-eslint": "^8.58.0"
|
"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
@@ -22,7 +22,7 @@ const Clanes: FC = () => {
|
|||||||
<div
|
<div
|
||||||
className={card({ variant: 'glass' }).content}
|
className={card({ variant: 'glass' }).content}
|
||||||
>
|
>
|
||||||
<Typography variant="h2" align="center">Clanes</Typography>
|
<Typography variant="h2" align='center'>Clanes</Typography>
|
||||||
<div
|
<div
|
||||||
className={css({
|
className={css({
|
||||||
display: 'grid',
|
display: 'grid',
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ import { alert } from '@/styled-system/recipes/alert'
|
|||||||
import { faTimes } from '@fortawesome/free-solid-svg-icons'
|
import { faTimes } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import { AnimatePresence, motion } from 'framer-motion'
|
import { AnimatePresence, motion } from 'framer-motion'
|
||||||
import type { FC } from 'react'
|
import { type FC } from 'react'
|
||||||
import { createPortal } from 'react-dom'
|
import { createPortal } from 'react-dom'
|
||||||
|
|
||||||
const FeedbackConsumer: FC = () => {
|
const FeedbackConsumer: FC = () => {
|
||||||
const { alerts } = useAppSelector((state) => state.feedback)
|
const { alerts } = useAppSelector(state => state.feedback)
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -55,7 +55,7 @@ const FeedbackConsumer: FC = () => {
|
|||||||
className={alert().closeButton}
|
className={alert().closeButton}
|
||||||
onClick={() => dispatch(removeAlert(currentAlert.id))}
|
onClick={() => dispatch(removeAlert(currentAlert.id))}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faTimes} size="sm" />
|
<FontAwesomeIcon icon={faTimes} fixedWidth size='sm'/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Typography variant="h3" component="div">
|
<Typography variant="h3" component="div">
|
||||||
{currentAlert.title}
|
{currentAlert.title}
|
||||||
|
|||||||
+9
-9
@@ -111,20 +111,20 @@ const Hero: FC = () => {
|
|||||||
color: 'primary',
|
color: 'primary',
|
||||||
size: 'large'
|
size: 'large'
|
||||||
}), css({
|
}), css({
|
||||||
'position': 'absolute',
|
position: 'absolute',
|
||||||
'bottom': '45px',
|
bottom: '45px',
|
||||||
'right': '50%',
|
right: '50%',
|
||||||
'animationName': 'bounce',
|
animationName: 'bounce',
|
||||||
'animationDuration': '1s',
|
animationDuration: '1s',
|
||||||
'animationIterationCount': 'infinite',
|
animationIterationCount: 'infinite',
|
||||||
'transform': 'translateX(50%)',
|
transform: 'translateX(50%)',
|
||||||
'zIndex': 1,
|
zIndex: 1,
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
animationPlayState: 'paused'
|
animationPlayState: 'paused'
|
||||||
}
|
}
|
||||||
}))}
|
}))}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faArrowDown} size="lg" />
|
<FontAwesomeIcon icon={faArrowDown} size='lg' fixedWidth />
|
||||||
</a>
|
</a>
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { setClanes, setCurrentUser, setSession, setStatus } from '@/state/sessio
|
|||||||
import { AppwriteException } from 'appwrite'
|
import { AppwriteException } from 'appwrite'
|
||||||
import { getClanes } from 'entgamers-database/frontend/clanes'
|
import { getClanes } from 'entgamers-database/frontend/clanes'
|
||||||
import { getCurrentUser, getSession } from 'entgamers-database/frontend/session'
|
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 SessionConsumer: FC = () => {
|
||||||
const { status, session, user, clanes } = useAppSelector((state) => state.session)
|
const { status, session, user, clanes } = useAppSelector((state) => state.session)
|
||||||
@@ -13,6 +13,7 @@ const SessionConsumer: FC = () => {
|
|||||||
|
|
||||||
const ensureSession = useCallback(async () => {
|
const ensureSession = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
|
if (status !== 'initializing' || session !== undefined) return
|
||||||
dispatch(setStatus('loading'))
|
dispatch(setStatus('loading'))
|
||||||
const currentSession = await getSession('current')
|
const currentSession = await getSession('current')
|
||||||
const currentUser = await getCurrentUser()
|
const currentUser = await getCurrentUser()
|
||||||
@@ -25,17 +26,16 @@ const SessionConsumer: FC = () => {
|
|||||||
} finally {
|
} finally {
|
||||||
dispatch(setStatus('idle'))
|
dispatch(setStatus('idle'))
|
||||||
}
|
}
|
||||||
}, [dispatch])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (status !== 'initializing' || session !== undefined) return
|
|
||||||
ensureSession()
|
ensureSession()
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
if (error instanceof AppwriteException) {
|
if (error instanceof AppwriteException) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [status, session, ensureSession])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (user !== undefined && clanes === undefined) {
|
if (user !== undefined && clanes === undefined) {
|
||||||
@@ -51,7 +51,11 @@ const SessionConsumer: FC = () => {
|
|||||||
} else if (user === undefined && clanes !== undefined) {
|
} else if (user === undefined && clanes !== undefined) {
|
||||||
dispatch(setClanes())
|
dispatch(setClanes())
|
||||||
}
|
}
|
||||||
}, [user, clanes, dispatch])
|
}, [user])
|
||||||
return null
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
export default SessionConsumer
|
export default SessionConsumer
|
||||||
|
|||||||
+1
-1
@@ -52,7 +52,7 @@ const Social: FC = () => {
|
|||||||
<div
|
<div
|
||||||
className={card({ variant: 'glass' }).content}
|
className={card({ variant: 'glass' }).content}
|
||||||
>
|
>
|
||||||
<Typography variant="h2" align="center">Redes Sociales</Typography>
|
<Typography variant="h2" align='center'>Redes Sociales</Typography>
|
||||||
<Typography variant="body1">
|
<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?
|
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>
|
</Typography>
|
||||||
|
|||||||
+1
-1
@@ -84,7 +84,7 @@ const Team: FC = () => {
|
|||||||
className={iconButton()}
|
className={iconButton()}
|
||||||
href={socialNetwork.url}
|
href={socialNetwork.url}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={socialNetwork.icon} />
|
<FontAwesomeIcon icon={socialNetwork.icon} fixedWidth />
|
||||||
</a>
|
</a>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+14
-55
@@ -3,7 +3,7 @@ import { css } from '@/styled-system/css'
|
|||||||
import { Container } from '@/styled-system/jsx'
|
import { Container } from '@/styled-system/jsx'
|
||||||
import { faChevronRight } from '@fortawesome/free-solid-svg-icons'
|
import { faChevronRight } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import type { FC } from 'react'
|
import { type FC } from 'react'
|
||||||
|
|
||||||
const ClanesPage: FC = () => {
|
const ClanesPage: FC = () => {
|
||||||
return (
|
return (
|
||||||
@@ -21,78 +21,37 @@ const ClanesPage: FC = () => {
|
|||||||
<Typography variant="h2">Beneficios de los clanes</Typography>
|
<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>
|
<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">
|
<ul className="fa-ul">
|
||||||
<li>
|
<li><FontAwesomeIcon icon={faChevronRight} listItem /> Espacio en el servidor de Discord.</li>
|
||||||
<span className="fa-li"><FontAwesomeIcon icon={faChevronRight} /></span>
|
<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>
|
||||||
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>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Typography variant="h2">Requisitos para formar un clan</Typography>
|
<Typography variant="h2">Requisitos para formar un clan</Typography>
|
||||||
<Typography variant="body1">Todos los clanes deben cumplir con los siguientes requisitos:</Typography>
|
<Typography variant="body1">Todos los clanes deben cumplir con los siguientes requisitos:</Typography>
|
||||||
<ul className="fa-ul">
|
<ul className="fa-ul">
|
||||||
<li>
|
<li><FontAwesomeIcon icon={faChevronRight} listItem /> Tener un encargado.</li>
|
||||||
<span className="fa-li">
|
<li><FontAwesomeIcon icon={faChevronRight} listItem /> Fomentar el compañerismo y la comunidad.</li>
|
||||||
<FontAwesomeIcon icon={faChevronRight} />
|
<li><FontAwesomeIcon icon={faChevronRight} listItem /> Aportar contenido de forma periódica para la comunidad.</li>
|
||||||
</span>
|
<li><FontAwesomeIcon icon={faChevronRight} listItem /> Realizar al menos una actividad mensual con los integrantes.</li>
|
||||||
{' '}
|
|
||||||
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>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Typography variant="h2">Clanes activos</Typography>
|
<Typography variant="h2">Clanes activos</Typography>
|
||||||
<div
|
<div
|
||||||
className={css({
|
className={css({
|
||||||
'backgroundColor': 'info',
|
backgroundColor: 'info',
|
||||||
'color': 'info.contrast',
|
color: 'info.contrast',
|
||||||
'borderRadius': 'medium',
|
borderRadius: 'medium',
|
||||||
'padding': 'medium',
|
padding: 'medium',
|
||||||
'marginBlock': 'medium',
|
marginBlock: 'medium',
|
||||||
'& a': {
|
'& a': {
|
||||||
color: 'info.contrast',
|
color: 'info.contrast',
|
||||||
fontWeight: 'bold'
|
fontWeight: 'bold'
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
Esta sección está en construcción. Puedes ver los clanes activos en nuestro
|
Esta sección está en construcción. Puedes ver los clanes activos en nuestro <a href="http://discord.gg/nqwzHJC">Servidor de Discord</a>.
|
||||||
{' '}
|
|
||||||
<a href="http://discord.gg/nqwzHJC">Servidor de Discord</a>
|
|
||||||
.
|
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ const CuentaTabs: FC = () => {
|
|||||||
>
|
>
|
||||||
<AnimatePresence
|
<AnimatePresence
|
||||||
initial={false}
|
initial={false}
|
||||||
mode="wait"
|
mode='wait'
|
||||||
>
|
>
|
||||||
{currentTab === 'login' && (
|
{currentTab === 'login' && (
|
||||||
<motion.div
|
<motion.div
|
||||||
@@ -52,8 +52,7 @@ const CuentaTabs: FC = () => {
|
|||||||
initial={{ opacity: 0, x: '-100%' }}
|
initial={{ opacity: 0, x: '-100%' }}
|
||||||
animate={{ opacity: 1, x: 0 }}
|
animate={{ opacity: 1, x: 0 }}
|
||||||
exit={{ opacity: 0, x: '100%' }}
|
exit={{ opacity: 0, x: '100%' }}
|
||||||
key="login"
|
key="login">
|
||||||
>
|
|
||||||
<UpdateEmail />
|
<UpdateEmail />
|
||||||
<UpdatePassword />
|
<UpdatePassword />
|
||||||
</motion.div>
|
</motion.div>
|
||||||
@@ -64,8 +63,7 @@ const CuentaTabs: FC = () => {
|
|||||||
initial={{ opacity: 0, x: '-100%' }}
|
initial={{ opacity: 0, x: '-100%' }}
|
||||||
animate={{ opacity: 1, x: 0 }}
|
animate={{ opacity: 1, x: 0 }}
|
||||||
exit={{ opacity: 0, x: '100%' }}
|
exit={{ opacity: 0, x: '100%' }}
|
||||||
key="perfil"
|
key="perfil">
|
||||||
>
|
|
||||||
<UpdateUserName />
|
<UpdateUserName />
|
||||||
<UpdateUserPreferences />
|
<UpdateUserPreferences />
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ const UpdateUserName: FC = () => {
|
|||||||
})
|
})
|
||||||
.catch(console.error)
|
.catch(console.error)
|
||||||
}
|
}
|
||||||
}, [status, session, user, formik])
|
}, [status, session, user])
|
||||||
|
|
||||||
if (status !== 'idle' || session === undefined) {
|
if (status !== 'idle' || session === undefined) {
|
||||||
// TODO: Replace with Skeleton
|
// TODO: Replace with Skeleton
|
||||||
@@ -99,7 +99,8 @@ const UpdateUserName: FC = () => {
|
|||||||
<Typography variant="caption" color="danger">{formik.errors.name}</Typography>
|
<Typography variant="caption" color="danger">{formik.errors.name}</Typography>
|
||||||
)}
|
)}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup>
|
<FormGroup
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={formik.isSubmitting || !formik.isValid}
|
disabled={formik.isSubmitting || !formik.isValid}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ const UpdateUserPreferences: FC = () => {
|
|||||||
})
|
})
|
||||||
.catch(console.error)
|
.catch(console.error)
|
||||||
}
|
}
|
||||||
}, [status, user, formik, session])
|
}, [status, session])
|
||||||
|
|
||||||
if (status !== 'idle' || session === undefined) {
|
if (status !== 'idle' || session === undefined) {
|
||||||
// TODO: Replace with Skeleton
|
// TODO: Replace with Skeleton
|
||||||
@@ -65,7 +65,7 @@ const UpdateUserPreferences: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Typography
|
<Typography
|
||||||
variant="h3"
|
variant='h3'
|
||||||
>
|
>
|
||||||
Preferencias
|
Preferencias
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -74,13 +74,13 @@ const UpdateUserPreferences: FC = () => {
|
|||||||
>
|
>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<label
|
<label
|
||||||
htmlFor="bio"
|
htmlFor='bio'
|
||||||
>
|
>
|
||||||
Biografia
|
Biografia
|
||||||
</label>
|
</label>
|
||||||
<TextArea
|
<TextArea
|
||||||
id="bio"
|
id='bio'
|
||||||
name="bio"
|
name='bio'
|
||||||
value={formik.values.bio}
|
value={formik.values.bio}
|
||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
onBlur={formik.handleBlur}
|
onBlur={formik.handleBlur}
|
||||||
@@ -96,7 +96,7 @@ const UpdateUserPreferences: FC = () => {
|
|||||||
{/* TODO: Add Profile Picture and Social Links fields */}
|
{/* TODO: Add Profile Picture and Social Links fields */}
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type='submit'
|
||||||
disabled={formik.isSubmitting || !formik.isValid}
|
disabled={formik.isSubmitting || !formik.isValid}
|
||||||
fullWidth
|
fullWidth
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Typography from '@/components/ui/Typography'
|
import Typography from '@/components/ui/Typography'
|
||||||
import { Container } from '@/styled-system/jsx'
|
import { Container } from '@/styled-system/jsx'
|
||||||
import type { FC } from 'react'
|
import { type FC } from 'react'
|
||||||
import CuentaTabs from './CuentaTabs'
|
import CuentaTabs from './CuentaTabs'
|
||||||
|
|
||||||
const CuentaPage: FC = () => {
|
const CuentaPage: FC = () => {
|
||||||
@@ -10,7 +10,7 @@ const CuentaPage: FC = () => {
|
|||||||
<Typography variant="body1">
|
<Typography variant="body1">
|
||||||
Desde aquí puedes administrar las preferencias y ajustes de tu cuenta.
|
Desde aquí puedes administrar las preferencias y ajustes de tu cuenta.
|
||||||
</Typography>
|
</Typography>
|
||||||
<CuentaTabs />
|
<CuentaTabs/>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ const DashboardTabs: FC = () => {
|
|||||||
>
|
>
|
||||||
<AnimatePresence
|
<AnimatePresence
|
||||||
initial={false}
|
initial={false}
|
||||||
mode="wait"
|
mode='wait'
|
||||||
>
|
>
|
||||||
{currentTab === undefined && (
|
{currentTab === undefined && (
|
||||||
<motion.div
|
<motion.div
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const ApplicationsFilter: FC<ApplicationsFilterProps> = ({ column }) => {
|
|||||||
<StatusSelector
|
<StatusSelector
|
||||||
id={`${column.id}-status-filter`}
|
id={`${column.id}-status-filter`}
|
||||||
value={columnFilterValue as TeamApplicationStatus}
|
value={columnFilterValue as TeamApplicationStatus}
|
||||||
onChange={(value) => { column.setFilterValue(value) }}
|
onChange={value => { column.setFilterValue(value) }}
|
||||||
allowEmpty
|
allowEmpty
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@@ -26,7 +26,7 @@ const ApplicationsFilter: FC<ApplicationsFilterProps> = ({ column }) => {
|
|||||||
<RoleSelector
|
<RoleSelector
|
||||||
id={`${column.id}-role-filter`}
|
id={`${column.id}-role-filter`}
|
||||||
value={columnFilterValue as TeamApplicationRole}
|
value={columnFilterValue as TeamApplicationRole}
|
||||||
onChange={(value) => { column.setFilterValue(value) }}
|
onChange={value => { column.setFilterValue(value) }}
|
||||||
allowEmpty
|
allowEmpty
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@@ -36,7 +36,7 @@ const ApplicationsFilter: FC<ApplicationsFilterProps> = ({ column }) => {
|
|||||||
fullWidth
|
fullWidth
|
||||||
type="text"
|
type="text"
|
||||||
value={(columnFilterValue ?? '') as string}
|
value={(columnFilterValue ?? '') as string}
|
||||||
onChange={(value) => { column.setFilterValue(value) }}
|
onChange={value => { column.setFilterValue(value) }}
|
||||||
placeholder="Buscar..."
|
placeholder="Buscar..."
|
||||||
className="w-36 border shadow rounded"
|
className="w-36 border shadow rounded"
|
||||||
list={column.id + 'list'}
|
list={column.id + 'list'}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Table, TableBody, TableCell, TableContainer, TableHead, TableHeadCell,
|
|||||||
import useManageError from '@/hooks/useManageError'
|
import useManageError from '@/hooks/useManageError'
|
||||||
import { css } from '@/styled-system/css'
|
import { css } from '@/styled-system/css'
|
||||||
import { formatDate } from '@/utilities/date'
|
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 { faChevronLeft, faChevronRight, faSort, faSortAsc, faSortDesc } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import { createColumnHelper, flexRender, getCoreRowModel, useReactTable, type ColumnFiltersState, type PaginationState, type RowData, type SortingState } from '@tanstack/react-table'
|
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', {
|
columnHelper.accessor('status', {
|
||||||
header: 'Estado',
|
header: 'Estado',
|
||||||
cell: StatusUpdater,
|
cell: StatusUpdater,
|
||||||
getUniqueValues() {
|
getUniqueValues () {
|
||||||
return ['Pending', 'Accepted', 'Rejected']
|
return ['Pending', 'Accepted', 'Rejected']
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@@ -125,7 +125,7 @@ const ApplicationsList: FC = () => {
|
|||||||
if (error instanceof Error && error.name === 'AbortError') return
|
if (error instanceof Error && error.name === 'AbortError') return
|
||||||
manageError(error, 'Error al obtener las aplicaciones', 'Error desconocido al obtener las aplicaciones', 'error')
|
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.
|
// TODO: Better UI Controls for: column visibility. Quantity selector.
|
||||||
return (
|
return (
|
||||||
@@ -145,9 +145,7 @@ const ApplicationsList: FC = () => {
|
|||||||
id={`${column.id}-view`}
|
id={`${column.id}-view`}
|
||||||
checked={column.getIsVisible()}
|
checked={column.getIsVisible()}
|
||||||
onChange={column.getToggleVisibilityHandler()}
|
onChange={column.getToggleVisibilityHandler()}
|
||||||
/>
|
/> {column.columnDef.header?.toString() ?? column.id}
|
||||||
{' '}
|
|
||||||
{column.columnDef.header?.toString() ?? column.id}
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -161,8 +159,8 @@ const ApplicationsList: FC = () => {
|
|||||||
<TableHeadCell
|
<TableHeadCell
|
||||||
key={header.id}
|
key={header.id}
|
||||||
className={css({
|
className={css({
|
||||||
'verticalAlign': 'top',
|
verticalAlign: 'top',
|
||||||
'position': 'relative',
|
position: 'relative',
|
||||||
'&:hover > [data-is-resizing]': {
|
'&:hover > [data-is-resizing]': {
|
||||||
backgroundColor: 'border'
|
backgroundColor: 'border'
|
||||||
}
|
}
|
||||||
@@ -189,27 +187,27 @@ const ApplicationsList: FC = () => {
|
|||||||
size="small"
|
size="small"
|
||||||
onClick={header.column.getToggleSortingHandler()}
|
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>
|
</IconButton>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{header.column.getCanFilter()
|
{header.column.getCanFilter()
|
||||||
? (
|
? (
|
||||||
<ApplicationsFilter column={header.column} />
|
<ApplicationsFilter column={header.column}/>
|
||||||
)
|
)
|
||||||
: null}
|
: null
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<div
|
||||||
type="button"
|
|
||||||
className={css({
|
className={css({
|
||||||
'position': 'absolute',
|
position: 'absolute',
|
||||||
'top': 0,
|
top: 0,
|
||||||
'right': 0,
|
right: 0,
|
||||||
'height': '100%',
|
height: '100%',
|
||||||
'width': '5px',
|
width: '5px',
|
||||||
'cursor': 'col-resize',
|
cursor: 'col-resize',
|
||||||
'userSelect': 'none',
|
userSelect: 'none',
|
||||||
'touchAction': 'none',
|
touchAction: 'none',
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
backgroundColor: 'border'
|
backgroundColor: 'border'
|
||||||
},
|
},
|
||||||
@@ -257,20 +255,14 @@ const ApplicationsList: FC = () => {
|
|||||||
onClick={() => { table.previousPage() }}
|
onClick={() => { table.previousPage() }}
|
||||||
disabled={!table.getCanPreviousPage()}
|
disabled={!table.getCanPreviousPage()}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faChevronLeft} />
|
<FontAwesomeIcon icon={faChevronLeft} fixedWidth />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
Pagina
|
Pagina {table.getState().pagination.pageIndex + 1} de {table.getPageCount()}
|
||||||
{' '}
|
|
||||||
{table.getState().pagination.pageIndex + 1}
|
|
||||||
{' '}
|
|
||||||
de
|
|
||||||
{' '}
|
|
||||||
{table.getPageCount()}
|
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => { table.nextPage() }}
|
onClick={() => { table.nextPage() }}
|
||||||
disabled={!table.getCanNextPage()}
|
disabled={!table.getCanNextPage()}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faChevronRight} />
|
<FontAwesomeIcon icon={faChevronRight} fixedWidth />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -15,17 +15,17 @@ const RoleSelector: FC<RoleSelectorProps> = ({ id, value, onChange, allowEmpty }
|
|||||||
<select
|
<select
|
||||||
id={`${id}-status`}
|
id={`${id}-status`}
|
||||||
className={css({
|
className={css({
|
||||||
'width': '100%',
|
width: '100%',
|
||||||
'border': 'none',
|
border: 'none',
|
||||||
'background': 'transparent',
|
background: 'transparent',
|
||||||
'color': 'inherit',
|
color: 'inherit',
|
||||||
'outline': 'none',
|
outline: 'none',
|
||||||
'cursor': 'pointer',
|
cursor: 'pointer',
|
||||||
'fontSize': 'inherit',
|
fontSize: 'inherit',
|
||||||
'fontWeight': 'inherit',
|
fontWeight: 'inherit',
|
||||||
'lineHeight': 'inherit',
|
lineHeight: 'inherit',
|
||||||
'padding': '0',
|
padding: '0',
|
||||||
'borderRadius': '0',
|
borderRadius: '0',
|
||||||
'&:focus': {
|
'&:focus': {
|
||||||
outline: 'none'
|
outline: 'none'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,17 +15,17 @@ const StatusSelector: FC<StatusSelectorProps> = ({ id, value, onChange, allowEmp
|
|||||||
<select
|
<select
|
||||||
id={`${id}-status`}
|
id={`${id}-status`}
|
||||||
className={css({
|
className={css({
|
||||||
'width': '100%',
|
width: '100%',
|
||||||
'border': 'none',
|
border: 'none',
|
||||||
'background': 'transparent',
|
background: 'transparent',
|
||||||
'color': 'inherit',
|
color: 'inherit',
|
||||||
'outline': 'none',
|
outline: 'none',
|
||||||
'cursor': 'pointer',
|
cursor: 'pointer',
|
||||||
'fontSize': 'inherit',
|
fontSize: 'inherit',
|
||||||
'fontWeight': 'inherit',
|
fontWeight: 'inherit',
|
||||||
'lineHeight': 'inherit',
|
lineHeight: 'inherit',
|
||||||
'padding': '0',
|
padding: '0',
|
||||||
'borderRadius': '0',
|
borderRadius: '0',
|
||||||
'&:focus': {
|
'&:focus': {
|
||||||
outline: 'none'
|
outline: 'none'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ const getTeams = async (): Promise<GetTeamsResponse> => {
|
|||||||
const moderatorMembers: Models.MembershipList = await getClanMembers(MODERATOR_CLAN_ID)
|
const moderatorMembers: Models.MembershipList = await getClanMembers(MODERATOR_CLAN_ID)
|
||||||
const collaboratorMembers: Models.MembershipList = await getClanMembers(COLLABORATOR_CLAN_ID)
|
const collaboratorMembers: Models.MembershipList = await getClanMembers(COLLABORATOR_CLAN_ID)
|
||||||
|
|
||||||
const adminsPromises = adminMembers.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 moderatorsPromises = moderatorMembers.memberships.map(async membership => await getUser(membership.userId))
|
||||||
const collaboratorsPromises = collaboratorMembers.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([
|
const [admins, moderators, collaborators] = await Promise.all([
|
||||||
Promise.all(adminsPromises), Promise.all(moderatorsPromises), Promise.all(collaboratorsPromises)
|
Promise.all(adminsPromises), Promise.all(moderatorsPromises), Promise.all(collaboratorsPromises)
|
||||||
@@ -96,7 +96,8 @@ const EquipoPage: FC = async () => {
|
|||||||
<Typography variant="body2" color="info">
|
<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.
|
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>
|
</Typography>
|
||||||
)}
|
)
|
||||||
|
}
|
||||||
<div className={center()}>
|
<div className={center()}>
|
||||||
<NextLink
|
<NextLink
|
||||||
className={button({ color: 'info' })}
|
className={button({ color: 'info' })}
|
||||||
@@ -157,7 +158,8 @@ const EquipoPage: FC = async () => {
|
|||||||
<Typography variant="body2" color="info">
|
<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.
|
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>
|
</Typography>
|
||||||
)}
|
)
|
||||||
|
}
|
||||||
<div className={center()}>
|
<div className={center()}>
|
||||||
<NextLink
|
<NextLink
|
||||||
className={button({ color: 'info' })}
|
className={button({ color: 'info' })}
|
||||||
@@ -218,7 +220,8 @@ const EquipoPage: FC = async () => {
|
|||||||
<Typography variant="body2" color="info">
|
<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.
|
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>
|
</Typography>
|
||||||
)}
|
)
|
||||||
|
}
|
||||||
<div className={center()}>
|
<div className={center()}>
|
||||||
<NextLink
|
<NextLink
|
||||||
className={button({ color: 'info' })}
|
className={button({ color: 'info' })}
|
||||||
|
|||||||
@@ -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 { createTeamApplication, type TeamApplicationData } from 'entgamers-database/frontend/database/teamApplications'
|
||||||
import { useFormik } from 'formik'
|
import { useFormik } from 'formik'
|
||||||
import { AnimatePresence, motion } from 'framer-motion'
|
import { AnimatePresence, motion } from 'framer-motion'
|
||||||
import { usePathname, useSearchParams } from 'next/navigation'
|
import { useSearchParams } from 'next/navigation'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
import { useEffect, type FC } from 'react'
|
import { useEffect, type FC } from 'react'
|
||||||
|
|
||||||
const ApplyForm: FC = () => {
|
const ApplyForm: FC = () => {
|
||||||
const searchParams = useSearchParams()
|
const searchParams = useSearchParams()
|
||||||
const pathname = usePathname()
|
|
||||||
const router = useRouter()
|
|
||||||
const { manageError } = useManageError()
|
const { manageError } = useManageError()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
@@ -57,11 +54,8 @@ const ApplyForm: FC = () => {
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
})
|
})
|
||||||
.finally(() => {
|
|
||||||
router.replace(pathname)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}, [searchParams, formik, pathname, router])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
@@ -76,7 +70,7 @@ const ApplyForm: FC = () => {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type='button'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
formik.setFieldValue('role', MODERATOR_CLAN_ID)
|
formik.setFieldValue('role', MODERATOR_CLAN_ID)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@@ -88,7 +82,7 @@ const ApplyForm: FC = () => {
|
|||||||
Moderador
|
Moderador
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type='button'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
formik.setFieldValue('role', ADMIN_CLAN_ID)
|
formik.setFieldValue('role', ADMIN_CLAN_ID)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@@ -100,7 +94,7 @@ const ApplyForm: FC = () => {
|
|||||||
Administrador
|
Administrador
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type='button'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
formik.setFieldValue('role', COLLABORATOR_CLAN_ID)
|
formik.setFieldValue('role', COLLABORATOR_CLAN_ID)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@@ -127,87 +121,90 @@ const ApplyForm: FC = () => {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<label htmlFor="name">Nombre</label>
|
<label htmlFor='name'>Nombre</label>
|
||||||
<Input
|
<Input
|
||||||
id="name"
|
id='name'
|
||||||
type="text"
|
type='text'
|
||||||
value={formik.values.name}
|
value={formik.values.name}
|
||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
onBlur={formik.handleBlur}
|
onBlur={formik.handleBlur}
|
||||||
/>
|
/>
|
||||||
{formik.touched.name !== undefined && formik.errors.name !== undefined
|
{formik.touched.name !== undefined && formik.errors.name !== undefined
|
||||||
? (
|
? (
|
||||||
<Typography variant="caption" color="danger">
|
<Typography variant='caption' color='danger'>
|
||||||
{formik.errors.name}
|
{formik.errors.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
<Typography variant="caption" color="info">
|
<Typography variant='caption' color='info'>
|
||||||
Tu nombre.
|
Tu nombre.
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<label htmlFor="email">Email</label>
|
<label htmlFor='email'>Email</label>
|
||||||
<Input
|
<Input
|
||||||
id="email"
|
id='email'
|
||||||
type="email"
|
type='email'
|
||||||
value={formik.values.email}
|
value={formik.values.email}
|
||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
onBlur={formik.handleBlur}
|
onBlur={formik.handleBlur}
|
||||||
/>
|
/>
|
||||||
{formik.touched.email !== undefined && formik.errors.email !== undefined
|
{formik.touched.email !== undefined && formik.errors.email !== undefined
|
||||||
? (
|
? (
|
||||||
<Typography variant="caption" color="danger">
|
<Typography variant='caption' color='danger'>
|
||||||
{formik.errors.email}
|
{formik.errors.email}
|
||||||
</Typography>
|
</Typography>
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
<Typography variant="caption" color="info">
|
<Typography variant='caption' color='info'>
|
||||||
Tu email, para poder contactarte.
|
Tu email, para poder contactarte.
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)
|
||||||
|
}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<label htmlFor="discord">Nombre de Discord</label>
|
<label htmlFor='discord'>Nombre de Discord</label>
|
||||||
<Input
|
<Input
|
||||||
id="discord"
|
id='discord'
|
||||||
type="text"
|
type='text'
|
||||||
value={formik.values.discord}
|
value={formik.values.discord}
|
||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
onBlur={formik.handleBlur}
|
onBlur={formik.handleBlur}
|
||||||
/>
|
/>
|
||||||
{formik.touched.discord !== undefined && formik.errors.discord !== undefined
|
{formik.touched.discord !== undefined && formik.errors.discord !== undefined
|
||||||
? (
|
? (
|
||||||
<Typography variant="caption" color="danger">
|
<Typography variant='caption' color='danger'>
|
||||||
{formik.errors.discord}
|
{formik.errors.discord}
|
||||||
</Typography>
|
</Typography>
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
<Typography variant="caption" color="info">
|
<Typography variant='caption' color='info'>
|
||||||
Tu nombre de Discord, para poder contactarte.
|
Tu nombre de Discord, para poder contactarte.
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)
|
||||||
|
}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<label htmlFor="message">Mensaje</label>
|
<label htmlFor='message'>Mensaje</label>
|
||||||
<TextArea
|
<TextArea
|
||||||
id="message"
|
id='message'
|
||||||
value={formik.values.message}
|
value={formik.values.message}
|
||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
onBlur={formik.handleBlur}
|
onBlur={formik.handleBlur}
|
||||||
/>
|
/>
|
||||||
{formik.touched.message !== undefined && formik.errors.message !== undefined
|
{formik.touched.message !== undefined && formik.errors.message !== undefined
|
||||||
? (
|
? (
|
||||||
<Typography variant="caption" color="danger">
|
<Typography variant='caption' color='danger'>
|
||||||
{formik.errors.message}
|
{formik.errors.message}
|
||||||
</Typography>
|
</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.
|
¿Por que te gustaría unirte al equipo?, ¿Que te gustaría hacer?, etc.
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)
|
||||||
|
}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<div
|
<div
|
||||||
className={css({
|
className={css({
|
||||||
@@ -215,7 +212,7 @@ const ApplyForm: FC = () => {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type='submit'
|
||||||
disabled={!formik.isValid || !formik.dirty}
|
disabled={!formik.isValid || !formik.dirty}
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|
||||||
@@ -242,13 +239,14 @@ const ApplyForm: FC = () => {
|
|||||||
justifyContent: 'center'
|
justifyContent: 'center'
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Typography variant="h2" align="center">¡Gracias por interesarte en unirte al equipo!</Typography>
|
<Typography variant='h2' align="center">¡Gracias por interesarte en unirte al equipo!</Typography>
|
||||||
<Typography variant="body1">
|
<Typography variant='body1'>
|
||||||
El equipo de EntGamers se pondrá en contacto contigo a la brevedad posible.
|
El equipo de EntGamers se pondrá en contacto contigo a la brevedad posible.
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)
|
||||||
|
}
|
||||||
<div
|
<div
|
||||||
className={css({
|
className={css({
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
@@ -256,39 +254,31 @@ const ApplyForm: FC = () => {
|
|||||||
paddingBlock: 'medium'
|
paddingBlock: 'medium'
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<AnimatePresence mode="wait" initial={false}>
|
<AnimatePresence mode='wait' initial={false}>
|
||||||
{formik.values.role === MODERATOR_CLAN_ID && (
|
{formik.values.role === MODERATOR_CLAN_ID && (
|
||||||
<motion.div
|
<motion.div
|
||||||
key="motion-moderator"
|
key={'motion-moderator'}
|
||||||
transition={{ duration: 0.15, ease: 'easeInOut' }}
|
transition={{ duration: 0.15, ease: 'easeInOut' }}
|
||||||
initial={{ opacity: 0, x: '-250px' }}
|
initial={{ opacity: 0, x: '-250px' }}
|
||||||
animate={{ opacity: 1, x: 0 }}
|
animate={{ opacity: 1, x: 0 }}
|
||||||
exit={{ opacity: 0, x: '250px' }}
|
exit={{ opacity: 0, x: '250px' }}
|
||||||
>
|
>
|
||||||
<Typography variant="h2" align="center">Moderadores</Typography>
|
<Typography variant='h2' align="center">Moderadores</Typography>
|
||||||
<Typography variant="body1">
|
<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.
|
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>
|
||||||
<Typography variant="h3">Requisitos</Typography>
|
<Typography variant='h3'>Requisitos</Typography>
|
||||||
<ul className="fa-ul">
|
<ul className="fa-ul">
|
||||||
<li>
|
<li>
|
||||||
<span className="fa-li">
|
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Imparcialidad</strong>
|
||||||
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
|
|
||||||
</span>
|
|
||||||
{' '}
|
|
||||||
<strong>Imparcialidad</strong>
|
|
||||||
<br />
|
<br />
|
||||||
La comunidad esta conformada por amigos y conocidos, por lo tanto es importante poder actuar de forma imparcial y responsable.
|
La comunidad esta conformada por amigos y conocidos, por lo tanto es importante poder actuar de forma imparcial y responsable.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<Typography variant="h3">Beneficios</Typography>
|
<Typography variant='h3'>Beneficios</Typography>
|
||||||
<ul className="fa-ul">
|
<ul className="fa-ul">
|
||||||
<li>
|
<li>
|
||||||
<span className="fa-li">
|
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Experiencia</strong>
|
||||||
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
|
|
||||||
</span>
|
|
||||||
{' '}
|
|
||||||
<strong>Experiencia</strong>
|
|
||||||
<br />
|
<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.
|
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>
|
||||||
@@ -297,36 +287,28 @@ const ApplyForm: FC = () => {
|
|||||||
)}
|
)}
|
||||||
{formik.values.role === COLLABORATOR_CLAN_ID && (
|
{formik.values.role === COLLABORATOR_CLAN_ID && (
|
||||||
<motion.div
|
<motion.div
|
||||||
key="motion-collaborator"
|
key={'motion-collaborator'}
|
||||||
transition={{ duration: 0.15, ease: 'easeInOut' }}
|
transition={{ duration: 0.15, ease: 'easeInOut' }}
|
||||||
initial={{ opacity: 0, x: '-250px' }}
|
initial={{ opacity: 0, x: '-250px' }}
|
||||||
animate={{ opacity: 1, x: 0 }}
|
animate={{ opacity: 1, x: 0 }}
|
||||||
exit={{ opacity: 0, x: '250px' }}
|
exit={{ opacity: 0, x: '250px' }}
|
||||||
>
|
>
|
||||||
<Typography variant="h2" align="center">Colaborador</Typography>
|
<Typography variant='h2' align='center'>Colaborador</Typography>
|
||||||
<Typography variant="body1">
|
<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.
|
Los colaboradores son personas ajenas al staff central de EntGamers que nos ayudan a traer contenido, eventos y actividades a la comunidad.
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="h3">Requisitos</Typography>
|
<Typography variant='h3'>Requisitos</Typography>
|
||||||
<ul className="fa-ul">
|
<ul className="fa-ul">
|
||||||
<li>
|
<li>
|
||||||
<span className="fa-li">
|
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Profesionalismo</strong>
|
||||||
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
|
|
||||||
</span>
|
|
||||||
{' '}
|
|
||||||
<strong>Profesionalismo</strong>
|
|
||||||
<br />
|
<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.
|
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>
|
||||||
</ul>
|
</ul>
|
||||||
<Typography variant="h3">Beneficios</Typography>
|
<Typography variant='h3'>Beneficios</Typography>
|
||||||
<ul className="fa-ul">
|
<ul className="fa-ul">
|
||||||
<li>
|
<li>
|
||||||
<span className="fa-li">
|
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Apoyo</strong>
|
||||||
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
|
|
||||||
</span>
|
|
||||||
{' '}
|
|
||||||
<strong>Apoyo</strong>
|
|
||||||
<br />
|
<br />
|
||||||
Puedes contar con el apoyo de la comunidad para tus proyectos, ya sea en forma de difusión, asesoramiento o recursos.
|
Puedes contar con el apoyo de la comunidad para tus proyectos, ya sea en forma de difusión, asesoramiento o recursos.
|
||||||
</li>
|
</li>
|
||||||
@@ -335,63 +317,43 @@ const ApplyForm: FC = () => {
|
|||||||
)}
|
)}
|
||||||
{formik.values.role === ADMIN_CLAN_ID && (
|
{formik.values.role === ADMIN_CLAN_ID && (
|
||||||
<motion.div
|
<motion.div
|
||||||
key="motion-administrator"
|
key={'motion-administrator'}
|
||||||
transition={{ duration: 0.15, ease: 'easeInOut' }}
|
transition={{ duration: 0.15, ease: 'easeInOut' }}
|
||||||
initial={{ opacity: 0, x: '-250px' }}
|
initial={{ opacity: 0, x: '-250px' }}
|
||||||
animate={{ opacity: 1, x: 0 }}
|
animate={{ opacity: 1, x: 0 }}
|
||||||
exit={{ opacity: 0, x: '250px' }}
|
exit={{ opacity: 0, x: '250px' }}
|
||||||
>
|
>
|
||||||
<Typography variant="h2" align="center">Administradores</Typography>
|
<Typography variant='h2' align='center'>Administradores</Typography>
|
||||||
<Typography variant="body1">
|
<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.
|
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>
|
||||||
<Typography variant="h3">Requisitos</Typography>
|
<Typography variant='h3'>Requisitos</Typography>
|
||||||
<ul className="fa-ul">
|
<ul className="fa-ul">
|
||||||
<li>
|
<li>
|
||||||
<span className="fa-li">
|
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Profesionalismo</strong>
|
||||||
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
|
|
||||||
</span>
|
|
||||||
{' '}
|
|
||||||
<strong>Profesionalismo</strong>
|
|
||||||
<br />
|
<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.
|
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>
|
||||||
<li>
|
<li>
|
||||||
<span className="fa-li">
|
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Constancia</strong>
|
||||||
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
|
|
||||||
</span>
|
|
||||||
{' '}
|
|
||||||
<strong>Constancia</strong>
|
|
||||||
<br />
|
<br />
|
||||||
La comunidad busca gente que en sus posibilidades sea activa, que pueda estar al tanto de lo que pasa en ella.
|
La comunidad busca gente que en sus posibilidades sea activa, que pueda estar al tanto de lo que pasa en ella.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span className="fa-li">
|
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Proactividad</strong>
|
||||||
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
|
|
||||||
</span>
|
|
||||||
{' '}
|
|
||||||
<strong>Proactividad</strong>
|
|
||||||
<br />
|
<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.
|
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>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<Typography variant="h3">Beneficios</Typography>
|
<Typography variant='h3'>Beneficios</Typography>
|
||||||
<ul className="fa-ul">
|
<ul className="fa-ul">
|
||||||
<li>
|
<li>
|
||||||
<span className="fa-li">
|
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Experiencia</strong>
|
||||||
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
|
|
||||||
</span>
|
|
||||||
{' '}
|
|
||||||
<strong>Experiencia</strong>
|
|
||||||
<br />
|
<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.
|
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>
|
||||||
<li>
|
<li>
|
||||||
<span className="fa-li">
|
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <strong>Capacitación</strong>
|
||||||
<FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} />
|
|
||||||
</span>
|
|
||||||
{' '}
|
|
||||||
<strong>Capacitación</strong>
|
|
||||||
<br />
|
<br />
|
||||||
La comunidad buscara dar capacitación a sus miembros en lo referido a herramientas y procedimientos utilizados.
|
La comunidad buscara dar capacitación a sus miembros en lo referido a herramientas y procedimientos utilizados.
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import Typography from '@/components/ui/Typography'
|
import Typography from '@/components/ui/Typography'
|
||||||
import { Container } from '@/styled-system/jsx'
|
import { Container } from '@/styled-system/jsx'
|
||||||
import { ensureTeamApplicationsCollection } from 'entgamers-database/backend/database/teamApplications'
|
import { ensureTeamApplicationsCollection } from 'entgamers-database/backend/database/teamApplications'
|
||||||
import { Suspense, type FC } from 'react'
|
import { type FC } from 'react'
|
||||||
import ApplyForm from './ApplyForm'
|
import ApplyForm from './ApplyForm'
|
||||||
|
|
||||||
const EquipoUnirsePage: FC = async () => {
|
const EquipoUnirsePage: FC = async () => {
|
||||||
@@ -12,9 +12,7 @@ const EquipoUnirsePage: FC = async () => {
|
|||||||
<Typography variant="body1">
|
<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.
|
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>
|
</Typography>
|
||||||
<Suspense fallback={<Typography variant="body1">Cargando...</Typography>}>
|
<ApplyForm />
|
||||||
<ApplyForm />
|
|
||||||
</Suspense>
|
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -8,8 +8,8 @@ import '@fontsource/open-sans/latin-700.css'
|
|||||||
import '@fontsource/permanent-marker/latin-400.css'
|
import '@fontsource/permanent-marker/latin-400.css'
|
||||||
import { config } from '@fortawesome/fontawesome-svg-core'
|
import { config } from '@fortawesome/fontawesome-svg-core'
|
||||||
import '@fortawesome/fontawesome-svg-core/styles.css'
|
import '@fortawesome/fontawesome-svg-core/styles.css'
|
||||||
import type { Metadata } from 'next'
|
import { type Metadata } from 'next'
|
||||||
import type { FC, ReactNode } from 'react'
|
import { type FC, type ReactNode } from 'react'
|
||||||
import FeedbackConsumer from './FeedbackConsumer'
|
import FeedbackConsumer from './FeedbackConsumer'
|
||||||
import SessionConsumer from './SessionConsumer'
|
import SessionConsumer from './SessionConsumer'
|
||||||
import StateProvider from './StateProvider'
|
import StateProvider from './StateProvider'
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ const LoginForm: FC = () => {
|
|||||||
if (session.status === 'idle' && session.session !== undefined) {
|
if (session.status === 'idle' && session.session !== undefined) {
|
||||||
router.push('/')
|
router.push('/')
|
||||||
}
|
}
|
||||||
}, [session, router])
|
}, [session])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
@@ -95,9 +95,7 @@ const LoginForm: FC = () => {
|
|||||||
)}
|
)}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<Typography variant="caption" color="muted">
|
<Typography variant="caption" color="muted">
|
||||||
¿Perdiste tu contraseña?
|
¿Perdiste tu contraseña? <NextLink href="/recover-password">Recupérala</NextLink>
|
||||||
{' '}
|
|
||||||
<NextLink href="/recover-password">Recupérala</NextLink>
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ const LoginPage: FC = () => {
|
|||||||
container(),
|
container(),
|
||||||
css({
|
css({
|
||||||
minHeight: 'calc(100vh - 60px - 72px)'
|
minHeight: 'calc(100vh - 60px - 72px)'
|
||||||
}))}
|
}))
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
@@ -40,10 +41,8 @@ const LoginPage: FC = () => {
|
|||||||
className={card().content}
|
className={card().content}
|
||||||
>
|
>
|
||||||
<LoginForm />
|
<LoginForm />
|
||||||
<Typography variant="caption" align="center">
|
<Typography variant="caption" align="center" >
|
||||||
¿No tienes una cuenta?
|
¿No tienes una cuenta? <NextLink href="/register">Regístrate</NextLink>
|
||||||
{' '}
|
|
||||||
<NextLink href="/register">Regístrate</NextLink>
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -68,11 +68,10 @@ const CreateRecoverPasswordForm: FC = () => {
|
|||||||
{formik.errors.email}
|
{formik.errors.email}
|
||||||
</Typography>
|
</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
|
||||||
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>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -1,23 +1,27 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import CreateRecoverPasswordForm from '@/app/recover-password/CreateRecoverPasswordForm'
|
import CreateRecoverPasswordForm from '@/app/recover-password/CreateRecoverPasswordForm'
|
||||||
import { useSearchParams } from 'next/navigation'
|
import { useSearchParams } from 'next/navigation'
|
||||||
import type { FC } from 'react'
|
import { useEffect, useState, type FC } from 'react'
|
||||||
import UpdateRecoverPasswordForm, { type UpdateRecoverPasswordFormProps } from './UpdateRecoverPasswordForm'
|
import UpdateRecoverPasswordForm, { type UpdateRecoverPasswordFormProps } from './UpdateRecoverPasswordForm'
|
||||||
|
|
||||||
const ManageRecoverPassword: FC = () => {
|
const ManageRecoverPassword: FC = () => {
|
||||||
|
const [recoverData, setRecoverData] = useState<UpdateRecoverPasswordFormProps | undefined>()
|
||||||
const searchParams = useSearchParams()
|
const searchParams = useSearchParams()
|
||||||
const userId = searchParams.get('userId')
|
|
||||||
const secret = searchParams.get('secret')
|
useEffect(() => {
|
||||||
const recoverData: UpdateRecoverPasswordFormProps | undefined = (userId !== null && secret !== null) ? { userId, secret } : undefined
|
const userId = searchParams.get('userId')
|
||||||
|
const secret = searchParams.get('secret')
|
||||||
|
if (userId !== null && secret !== null) {
|
||||||
|
setRecoverData({ userId, secret })
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
if (recoverData === undefined) {
|
if (recoverData === undefined) {
|
||||||
return <CreateRecoverPasswordForm />
|
return <CreateRecoverPasswordForm />
|
||||||
} else {
|
} else {
|
||||||
return (
|
return <UpdateRecoverPasswordForm
|
||||||
<UpdateRecoverPasswordForm
|
{...recoverData}
|
||||||
{...recoverData}
|
/>
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,8 @@ const UpdateRecoverPasswordForm: FC<UpdateRecoverPasswordFormProps> = (props) =>
|
|||||||
<Typography variant="caption" color="info">
|
<Typography variant="caption" color="info">
|
||||||
Escribe tu nueva contraseña
|
Escribe tu nueva contraseña
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)
|
||||||
|
}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<label htmlFor="confirmPassword">
|
<label htmlFor="confirmPassword">
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { css, cx } from '@/styled-system/css'
|
|||||||
import { Center } from '@/styled-system/jsx'
|
import { Center } from '@/styled-system/jsx'
|
||||||
import { container } from '@/styled-system/patterns'
|
import { container } from '@/styled-system/patterns'
|
||||||
import { card } from '@/styled-system/recipes'
|
import { card } from '@/styled-system/recipes'
|
||||||
import { Suspense, type FC } from 'react'
|
import { type FC } from 'react'
|
||||||
|
|
||||||
const page: FC = () => {
|
const page: FC = () => {
|
||||||
return (
|
return (
|
||||||
@@ -13,7 +13,8 @@ const page: FC = () => {
|
|||||||
container(),
|
container(),
|
||||||
css({
|
css({
|
||||||
minHeight: 'calc(100vh - 60px - 72px)'
|
minHeight: 'calc(100vh - 60px - 72px)'
|
||||||
}))}
|
}))
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
@@ -35,9 +36,7 @@ const page: FC = () => {
|
|||||||
<div
|
<div
|
||||||
className={card().content}
|
className={card().content}
|
||||||
>
|
>
|
||||||
<Suspense fallback={<Typography variant="body1">Cargando...</Typography>}>
|
<ManageRecoverPassword />
|
||||||
<ManageRecoverPassword />
|
|
||||||
</Suspense>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Center>
|
</Center>
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ const RegisterPage: FC = () => {
|
|||||||
container(),
|
container(),
|
||||||
css({
|
css({
|
||||||
minHeight: 'calc(100vh - 60px - 72px)'
|
minHeight: 'calc(100vh - 60px - 72px)'
|
||||||
}))}
|
}))
|
||||||
|
}
|
||||||
>
|
>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -41,10 +42,8 @@ const RegisterPage: FC = () => {
|
|||||||
className={card().content}
|
className={card().content}
|
||||||
>
|
>
|
||||||
<RegisterForm />
|
<RegisterForm />
|
||||||
<Typography variant="caption" align="center">
|
<Typography variant="caption" align="center" >
|
||||||
¿Ya tienes una cuenta?
|
¿Ya tienes una cuenta? <NextLink href="/login">Inicia sesión</NextLink>
|
||||||
{' '}
|
|
||||||
<NextLink href="/login">Inicia sesión</NextLink>
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Container } from '@/styled-system/jsx'
|
|||||||
import { faChevronRight, faHeart } from '@fortawesome/free-solid-svg-icons'
|
import { faChevronRight, faHeart } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import NextLink from 'next/link'
|
import NextLink from 'next/link'
|
||||||
import type { FC } from 'react'
|
import { type FC } from 'react'
|
||||||
|
|
||||||
const Footer: FC = () => {
|
const Footer: FC = () => {
|
||||||
return (
|
return (
|
||||||
@@ -22,24 +22,14 @@ const Footer: FC = () => {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<Typography variant="h3" component="div"> Acerca de </Typography>
|
<Typography variant="h3" component='div'> Acerca de </Typography>
|
||||||
<ul className="fa-ul">
|
<ul className="fa-ul">
|
||||||
<li>
|
<li><FontAwesomeIcon icon={faChevronRight} listItem fixedWidth /><NextLink href="/acerca-de"> EntGamers</NextLink></li>
|
||||||
<span className="fa-li">
|
<li><FontAwesomeIcon icon={faChevronRight} listItem fixedWidth /><NextLink href="/clanes"> Clanes</NextLink></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>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Typography variant="h3" component="div"> Contacto </Typography>
|
<Typography variant="h3" component='div'> Contacto </Typography>
|
||||||
</div>
|
</div>
|
||||||
<div></div>
|
<div></div>
|
||||||
</Container>
|
</Container>
|
||||||
@@ -50,14 +40,8 @@ const Footer: FC = () => {
|
|||||||
justifyContent: 'center'
|
justifyContent: 'center'
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Typography variant="body2" component="div">
|
<Typography variant="body2" component='div'>
|
||||||
Hecho con
|
Hecho con <FontAwesomeIcon className={css({ color: 'red' })} icon={faHeart} /> por <a href="https://srjuggernaut.dev">SrJuggernaut</a>
|
||||||
{' '}
|
|
||||||
<FontAwesomeIcon className={css({ color: 'red' })} icon={faHeart} />
|
|
||||||
{' '}
|
|
||||||
por
|
|
||||||
{' '}
|
|
||||||
<a href="https://srjuggernaut.dev">SrJuggernaut</a>
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</Container>
|
</Container>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -21,28 +21,28 @@ const Header: FC = () => {
|
|||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('scroll', handleScroll)
|
window.removeEventListener('scroll', handleScroll)
|
||||||
}
|
}
|
||||||
}, [handleScroll])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<header
|
<header
|
||||||
className={css({
|
className={css({
|
||||||
'display': 'flex',
|
display: 'flex',
|
||||||
'alignItems': 'center',
|
alignItems: 'center',
|
||||||
'justifyContent': 'center',
|
justifyContent: 'center',
|
||||||
'backgroundColor': 'transparent',
|
backgroundColor: 'transparent',
|
||||||
'color': 'text',
|
color: 'text',
|
||||||
'minHeight': '60px',
|
minHeight: '60px',
|
||||||
'position': 'fixed',
|
position: 'fixed',
|
||||||
'top': 0,
|
top: 0,
|
||||||
'left': 0,
|
left: 0,
|
||||||
'width': '100%',
|
width: '100%',
|
||||||
'zIndex': 'sticky',
|
zIndex: 'sticky',
|
||||||
'boxShadow': 'none',
|
boxShadow: 'none',
|
||||||
'transitionProperty': 'background-color, box-shadow',
|
transitionProperty: 'background-color, box-shadow',
|
||||||
'transitionDuration': '0.25s',
|
transitionDuration: '0.25s',
|
||||||
'transitionTimingFunction': 'easeInOut',
|
transitionTimingFunction: 'easeInOut',
|
||||||
'willChange': 'background-color, box-shadow',
|
willChange: 'background-color, box-shadow',
|
||||||
'&[data-scrolled=true]': {
|
'&[data-scrolled=true]': {
|
||||||
backgroundColor: 'surface',
|
backgroundColor: 'surface',
|
||||||
boxShadow: '2px 2px 4px 0px rgba(0, 0, 0, 0.25)'
|
boxShadow: '2px 2px 4px 0px rgba(0, 0, 0, 0.25)'
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|||||||
import { ADMIN_CLAN_ID, MODERATOR_CLAN_ID } from 'entgamers-database/frontend/clanes/administrative'
|
import { ADMIN_CLAN_ID, MODERATOR_CLAN_ID } from 'entgamers-database/frontend/clanes/administrative'
|
||||||
import { logout } from 'entgamers-database/frontend/session'
|
import { logout } from 'entgamers-database/frontend/session'
|
||||||
import NextLink from 'next/link'
|
import NextLink from 'next/link'
|
||||||
import type { FC } from 'react'
|
import { type FC } from 'react'
|
||||||
|
|
||||||
const SessionButtons: FC = () => {
|
const SessionButtons: FC = () => {
|
||||||
const { session, status, clanes } = useAppSelector((state) => state.session)
|
const { session, status, clanes } = useAppSelector(state => state.session)
|
||||||
const { manageError } = useManageError()
|
const { manageError } = useManageError()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
@@ -22,19 +22,21 @@ const SessionButtons: FC = () => {
|
|||||||
|
|
||||||
if (status === 'idle' && session === undefined) {
|
if (status === 'idle' && session === undefined) {
|
||||||
return (
|
return (
|
||||||
<Tooltip
|
<>
|
||||||
title="Iniciar sesión"
|
<Tooltip
|
||||||
position="bottom"
|
title={'Iniciar sesión'}
|
||||||
>
|
position='bottom'
|
||||||
<NextLink
|
|
||||||
href="/login"
|
|
||||||
className={
|
|
||||||
iconButton()
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faUser} />
|
<NextLink
|
||||||
</NextLink>
|
href="/login"
|
||||||
</Tooltip>
|
className={
|
||||||
|
iconButton()
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faUser} fixedWidth />
|
||||||
|
</NextLink>
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,8 +44,8 @@ const SessionButtons: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title="Mi cuenta"
|
title={'Mi cuenta'}
|
||||||
position="bottom"
|
position='bottom'
|
||||||
>
|
>
|
||||||
<NextLink
|
<NextLink
|
||||||
href="/cuenta"
|
href="/cuenta"
|
||||||
@@ -51,13 +53,13 @@ const SessionButtons: FC = () => {
|
|||||||
iconButton()
|
iconButton()
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faUser} />
|
<FontAwesomeIcon icon={faUser} fixedWidth />
|
||||||
</NextLink>
|
</NextLink>
|
||||||
</Tooltip>
|
</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
|
<Tooltip
|
||||||
title="Panel de administración"
|
title={'Panel de administración'}
|
||||||
position="bottom"
|
position='bottom'
|
||||||
>
|
>
|
||||||
<NextLink
|
<NextLink
|
||||||
href="/dashboard"
|
href="/dashboard"
|
||||||
@@ -65,13 +67,13 @@ const SessionButtons: FC = () => {
|
|||||||
iconButton()
|
iconButton()
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faCogs} />
|
<FontAwesomeIcon icon={faCogs} fixedWidth />
|
||||||
</NextLink>
|
</NextLink>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title="Cerrar sesión"
|
title={'Cerrar sesión'}
|
||||||
position="bottom"
|
position='bottom'
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -89,7 +91,7 @@ const SessionButtons: FC = () => {
|
|||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faRightFromBracket} />
|
<FontAwesomeIcon icon={faRightFromBracket} fixedWidth />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import BackDrop from '@/components/ui/BackDrop'
|
|||||||
import IconButton from '@/components/ui/IconButton'
|
import IconButton from '@/components/ui/IconButton'
|
||||||
import { css } from '@/styled-system/css'
|
import { css } from '@/styled-system/css'
|
||||||
import { iconButton } from '@/styled-system/recipes'
|
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 { faBars, faHome, faTimes, faUsers } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import NextLink from 'next/link'
|
import NextLink from 'next/link'
|
||||||
@@ -62,7 +62,6 @@ const Menu: FC = () => {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
|
||||||
className={iconButton({
|
className={iconButton({
|
||||||
color: 'danger'
|
color: 'danger'
|
||||||
})}
|
})}
|
||||||
@@ -81,21 +80,22 @@ const Menu: FC = () => {
|
|||||||
>
|
>
|
||||||
{menuLinks.map((menuLink, index) => (
|
{menuLinks.map((menuLink, index) => (
|
||||||
<li
|
<li
|
||||||
key={`menu-link-${menuLink.label}-${index.toString()}`}
|
key={`menu-link-${index}`}
|
||||||
|
onClick={() => { setIsMenuOpen(false) }}
|
||||||
>
|
>
|
||||||
<NextLink
|
<NextLink
|
||||||
className={css({
|
className={css({
|
||||||
'display': 'flex',
|
display: 'flex',
|
||||||
'alignItems': 'center',
|
alignItems: 'center',
|
||||||
'justifyContent': 'left',
|
justifyContent: 'left',
|
||||||
'padding': '1rem',
|
padding: '1rem',
|
||||||
'textDecoration': 'none',
|
textDecoration: 'none',
|
||||||
'backgroundColor': 'transparent',
|
backgroundColor: 'transparent',
|
||||||
'color': 'text',
|
color: 'text',
|
||||||
'transitionProperty': 'background-color',
|
transitionProperty: 'background-color',
|
||||||
'transitionDuration': 'normal',
|
transitionDuration: 'normal',
|
||||||
'transitionTimingFunction': 'easeInOut',
|
transitionTimingFunction: 'easeInOut',
|
||||||
'willChange': 'background-color color',
|
willChange: 'background-color color',
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
backgroundColor: 'primary',
|
backgroundColor: 'primary',
|
||||||
color: 'primary.contrast'
|
color: 'primary.contrast'
|
||||||
@@ -107,11 +107,8 @@ const Menu: FC = () => {
|
|||||||
})}
|
})}
|
||||||
href={menuLink.href}
|
href={menuLink.href}
|
||||||
data-active={pathName === menuLink.href}
|
data-active={pathName === menuLink.href}
|
||||||
onClick={() => { setIsMenuOpen(false) }}
|
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={menuLink.icon} />
|
<FontAwesomeIcon icon={menuLink.icon} fixedWidth /> {menuLink.label}
|
||||||
|
|
||||||
{menuLink.label}
|
|
||||||
</NextLink>
|
</NextLink>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { cx } from '@/styled-system/css'
|
import { cx } from '@/styled-system/css'
|
||||||
import { alert, type AlertVariantProps } from '@/styled-system/recipes/alert'
|
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 { faTimes } from '@fortawesome/free-solid-svg-icons/faTimes'
|
||||||
import { FontAwesomeIcon, type FontAwesomeIconProps } from '@fortawesome/react-fontawesome'
|
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'
|
import IconButton, { type IconButtonProps } from './IconButton'
|
||||||
|
|
||||||
type ComposedAlertProps = MergeOmitting<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, AlertVariantProps>
|
type ComposedAlertProps = MergeOmitting<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, AlertVariantProps>
|
||||||
@@ -32,8 +32,9 @@ export const AlertCloseButton: FC<ComposedAlertCloseButtonProps> = ({ children,
|
|||||||
{...allOtherAlertProps}
|
{...allOtherAlertProps}
|
||||||
>
|
>
|
||||||
{children === undefined
|
{children === undefined
|
||||||
? <FontAwesomeIcon icon={faTimes as FontAwesomeIconProps['icon']} size="sm" />
|
? <FontAwesomeIcon icon={faTimes as FontAwesomeIconProps['icon']} fixedWidth size='sm' />
|
||||||
: children}
|
: children
|
||||||
|
}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ const BackDrop: FC<BackDropProps> = ({ isOpen, onClickAway, children }) => {
|
|||||||
{children}
|
{children}
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)
|
)
|
||||||
: undefined}
|
: undefined
|
||||||
|
}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
), document.body)
|
), document.body)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { cx } from '@/styled-system/css'
|
import { cx } from '@/styled-system/css'
|
||||||
import { button, type ButtonVariantProps } from '@/styled-system/recipes/button'
|
import { button, type ButtonVariantProps } from '@/styled-system/recipes/button'
|
||||||
import type { MergeOmitting } from '@/types/utilities'
|
import { type MergeOmitting } from '@/types/utilities'
|
||||||
import type { ButtonHTMLAttributes, DetailedHTMLProps, FC } from 'react'
|
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 Button: FC<ButtonProps> = ({ children, className, ...rest }) => {
|
||||||
const [buttonRecipeArgs, allOtherButtonProps] = button.splitVariantProps(rest)
|
const [buttonRecipeArgs, allOtherButtonProps] = button.splitVariantProps(rest)
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { cx } from '@/styled-system/css'
|
import { cx } from '@/styled-system/css'
|
||||||
import { iconButton, type IconButtonVariantProps } from '@/styled-system/recipes/icon-button'
|
import { iconButton, type IconButtonVariantProps } from '@/styled-system/recipes/icon-button'
|
||||||
import type { MergeOmitting } from '@/types/utilities'
|
import { type MergeOmitting } from '@/types/utilities'
|
||||||
import type { ButtonHTMLAttributes, DetailedHTMLProps, FC } from 'react'
|
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 IconButton: FC<IconButtonProps> = ({ children, className, ...rest }) => {
|
||||||
const [iconButtonRecipeArgs, allOtherIconButtonProps] = iconButton.splitVariantProps(rest)
|
const [iconButtonRecipeArgs, allOtherIconButtonProps] = iconButton.splitVariantProps(rest)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { cx } from '@/styled-system/css'
|
import { cx } from '@/styled-system/css'
|
||||||
import { typography, type TypographyVariantProps } from '@/styled-system/recipes/typography'
|
import { typography, type TypographyVariantProps } from '@/styled-system/recipes/typography'
|
||||||
import type { MergeOmitting } from '@/types/utilities'
|
import { type MergeOmitting } from '@/types/utilities'
|
||||||
import { type ElementType, type FC, type HTMLAttributes, createElement } from 'react'
|
import { type ElementType, type FC, type HTMLAttributes } from 'react'
|
||||||
|
|
||||||
type ComposedTypographyProps = MergeOmitting<HTMLAttributes<HTMLElement>, TypographyVariantProps>
|
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 Typography: FC<TypographyProps> = ({ children, className, component, ...rest }) => {
|
||||||
const [typographyRecipeArgs, allOtherTypographyProps] = typography.splitVariantProps(rest)
|
const [typographyRecipeArgs, allOtherTypographyProps] = typography.splitVariantProps(rest)
|
||||||
|
const Component = component ?? variantToComponent(typographyRecipeArgs.variant)
|
||||||
typographyRecipeArgs.color = typographyRecipeArgs.color ?? (
|
typographyRecipeArgs.color = typographyRecipeArgs.color ?? (
|
||||||
typeof typographyRecipeArgs.variant === 'string' && typographyRecipeArgs.variant.startsWith('h')
|
typeof typographyRecipeArgs.variant === 'string' && typographyRecipeArgs.variant.startsWith('h')
|
||||||
? 'primary'
|
? 'primary'
|
||||||
: 'inherit'
|
: 'inherit'
|
||||||
)
|
)
|
||||||
return createElement(
|
return (
|
||||||
component ?? variantToComponent(typographyRecipeArgs.variant),
|
<Component
|
||||||
{
|
className={cx(typography(typographyRecipeArgs), className)}
|
||||||
className: cx(typography(typographyRecipeArgs), className),
|
{...allOtherTypographyProps}
|
||||||
...allOtherTypographyProps
|
>
|
||||||
},
|
{children}
|
||||||
children
|
</Component>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,16 +19,14 @@ const DebouncedInput: FC<DebouncedInputProps> = ({ value: initialValue, onChange
|
|||||||
onChange(value)
|
onChange(value)
|
||||||
}, debounce)
|
}, debounce)
|
||||||
|
|
||||||
return () => {
|
return () => { clearTimeout(timeout) }
|
||||||
clearTimeout(timeout)
|
}, [value])
|
||||||
}
|
|
||||||
}, [value, onChange, debounce])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Input
|
<Input
|
||||||
{...props}
|
{...props}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(e) => { setValue(e.target.value) }}
|
onChange={e => { setValue(e.target.value) }}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,21 @@
|
|||||||
import { cx } from '@/styled-system/css'
|
import { cx } from '@/styled-system/css'
|
||||||
import { input, type InputVariantProps } from '@/styled-system/recipes/input'
|
import { input, type InputVariantProps } from '@/styled-system/recipes/input'
|
||||||
import type { MergeOmitting } from '@/types/utilities'
|
import { type MergeOmitting } from '@/types/utilities'
|
||||||
import type { DetailedHTMLProps, FC, InputHTMLAttributes } from 'react'
|
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)
|
const [inputRecipeArgs, allOtherInputProps] = input.splitVariantProps(rest)
|
||||||
return (
|
return (
|
||||||
<input
|
<input
|
||||||
className={cx(input(inputRecipeArgs), className)}
|
className={cx(input(inputRecipeArgs), className)}
|
||||||
{...allOtherInputProps}
|
{...allOtherInputProps}
|
||||||
/>
|
>
|
||||||
|
{children}
|
||||||
|
</input>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import IconButton from '@/components/ui/IconButton'
|
|||||||
import Tooltip from '@/components/ui/Tooltip'
|
import Tooltip from '@/components/ui/Tooltip'
|
||||||
import { css, cx } from '@/styled-system/css'
|
import { css, cx } from '@/styled-system/css'
|
||||||
import { input, type InputVariantProps } from '@/styled-system/recipes/input'
|
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 { faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import { useState, type FC, type InputHTMLAttributes } from 'react'
|
import { useState, type FC, type InputHTMLAttributes } from 'react'
|
||||||
@@ -47,7 +47,7 @@ const PasswordInput: FC<InputProps> = ({ className, ...props }) => {
|
|||||||
size="small"
|
size="small"
|
||||||
onClick={() => { setShowPassword(!showPassword) }}
|
onClick={() => { setShowPassword(!showPassword) }}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={showPassword ? faEyeSlash : faEye} />
|
<FontAwesomeIcon icon={showPassword ? faEyeSlash : faEye} fixedWidth/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,16 +13,16 @@ const feedbackSlice = createSlice({
|
|||||||
name: 'feedback',
|
name: 'feedback',
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
addAlert(state, action: PayloadAction<Alert>) {
|
addAlert (state, action: PayloadAction<Alert>) {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
alerts: [...state.alerts, action.payload]
|
alerts: [...state.alerts, action.payload]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeAlert(state, action: PayloadAction<string>) {
|
removeAlert (state, action: PayloadAction<string>) {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
alerts: state.alerts.filter((alert) => alert.id !== action.payload)
|
alerts: state.alerts.filter(alert => alert.id !== action.payload)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -1,15 +1,15 @@
|
|||||||
import { createSlice, type PayloadAction } from '@reduxjs/toolkit'
|
import { createSlice, type PayloadAction } from '@reduxjs/toolkit'
|
||||||
import type { Models } from 'appwrite'
|
import { type Models } from 'appwrite'
|
||||||
import type { ClanList } from 'entgamers-database/frontend/clanes'
|
import { type ClanList } from 'entgamers-database/frontend/clanes'
|
||||||
import type { User } from 'entgamers-database/frontend/session'
|
import { type User } from 'entgamers-database/frontend/session'
|
||||||
|
|
||||||
export type SessionState
|
export type SessionState =
|
||||||
= | {
|
| {
|
||||||
status: 'idle' | 'loading' | 'initializing'
|
status: 'idle' | 'loading' | 'initializing'
|
||||||
session?: Models.Session
|
session?: Models.Session
|
||||||
user?: User
|
user?: User
|
||||||
clanes?: ClanList
|
clanes?: ClanList
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: SessionState = {
|
const initialState: SessionState = {
|
||||||
status: 'initializing'
|
status: 'initializing'
|
||||||
|
|||||||
+4
-5
@@ -12,11 +12,11 @@
|
|||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"module": "esnext",
|
"module": "Node16",
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "Node16",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "preserve",
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
"baseUrl": "src",
|
"baseUrl": "src",
|
||||||
"paths": {
|
"paths": {
|
||||||
@@ -35,8 +35,7 @@
|
|||||||
"**/*.ts",
|
"**/*.ts",
|
||||||
"**/*.tsx",
|
"**/*.tsx",
|
||||||
".next/types/**/*.ts",
|
".next/types/**/*.ts",
|
||||||
"next.config.js",
|
"next.config.js"
|
||||||
".next/dev/types/**/*.ts"
|
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules"
|
"node_modules"
|
||||||
|
|||||||
Reference in New Issue
Block a user