feat: static unirse
This commit is contained in:
+28
-28
@@ -30,16 +30,14 @@ const team: TeamMember[] = [
|
||||
const Team: FC = () => {
|
||||
return (
|
||||
<section
|
||||
className={css({
|
||||
className={center({
|
||||
minHeight: '75vh',
|
||||
backgroundImage: 'url(/images/backgrounds/MysteriousForest.jpg)'
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className={center()}
|
||||
>
|
||||
|
||||
<Container
|
||||
<Container>
|
||||
<div
|
||||
className={css({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
@@ -93,30 +91,32 @@ const Team: FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</Container>
|
||||
</div>
|
||||
<div
|
||||
className={css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-evenly',
|
||||
gap: 'medium',
|
||||
marginBlock: 'medium'
|
||||
})}
|
||||
>
|
||||
<NextLink
|
||||
className={button({ color: 'info' })}
|
||||
href="/equipo"
|
||||
|
||||
</div>
|
||||
<div
|
||||
className={css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-evenly',
|
||||
gap: 'medium',
|
||||
paddingBlock: 'large',
|
||||
width: '100%'
|
||||
})}
|
||||
>
|
||||
Ver el equipo completo
|
||||
</NextLink>
|
||||
<NextLink
|
||||
className={button({ color: 'primary' })}
|
||||
href="/equipo/join"
|
||||
>
|
||||
Únete al equipo
|
||||
</NextLink>
|
||||
</div>
|
||||
<NextLink
|
||||
className={button({ color: 'info' })}
|
||||
href="/equipo"
|
||||
>
|
||||
Ver el equipo completo
|
||||
</NextLink>
|
||||
<NextLink
|
||||
className={button({ color: 'primary' })}
|
||||
href="/equipo/unirse"
|
||||
>
|
||||
Únete al equipo
|
||||
</NextLink>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ const EquipoPage: FC = () => {
|
||||
<div className={center()}>
|
||||
<NextLink
|
||||
className={button({ color: 'info' })}
|
||||
href="/equipo/unirse"
|
||||
href="/equipo/unirse?role=moderator"
|
||||
>
|
||||
¡Quiero ser moderador!
|
||||
</NextLink>
|
||||
@@ -119,7 +119,7 @@ const EquipoPage: FC = () => {
|
||||
<div className={center()}>
|
||||
<NextLink
|
||||
className={button({ color: 'info' })}
|
||||
href="/equipo/unirse"
|
||||
href="/equipo/unirse?role=collaborator"
|
||||
>
|
||||
¡Quiero ser colaborador!
|
||||
</NextLink>
|
||||
|
||||
@@ -0,0 +1,286 @@
|
||||
'use client'
|
||||
import Button from '@/components/ui/Button'
|
||||
import Typography from '@/components/ui/Typography'
|
||||
import FormGroup from '@/components/ui/form/FormGroup'
|
||||
import Input from '@/components/ui/form/Input'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { type TeamApplyData } from '@/types/teamApply'
|
||||
import { faChevronRight } from '@fortawesome/free-solid-svg-icons'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { useFormik } from 'formik'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
import { useEffect, type FC } from 'react'
|
||||
|
||||
const ApplyForm: FC = () => {
|
||||
const searchParams = useSearchParams()
|
||||
|
||||
const formik = useFormik<TeamApplyData>({
|
||||
initialValues: {
|
||||
name: '',
|
||||
email: '',
|
||||
discordName: '',
|
||||
message: '',
|
||||
role: 'administrator'
|
||||
},
|
||||
onSubmit: (values) => {
|
||||
console.log(values)
|
||||
}
|
||||
})
|
||||
useEffect(() => {
|
||||
if (searchParams.has('role')) {
|
||||
formik.setFieldValue('role', searchParams.get('role'))
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
>
|
||||
<div
|
||||
className={css({
|
||||
display: 'flex',
|
||||
flexDirection: { base: 'column', md: 'row' },
|
||||
justifyContent: 'space-evenly',
|
||||
gap: 'medium'
|
||||
})}
|
||||
>
|
||||
<Button
|
||||
type='button'
|
||||
onClick={() => {
|
||||
formik.setFieldValue('role', 'moderator')
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
})
|
||||
}}
|
||||
disabled={formik.values.role === 'moderator'}
|
||||
>
|
||||
Moderador
|
||||
</Button>
|
||||
<Button
|
||||
type='button'
|
||||
onClick={() => {
|
||||
formik.setFieldValue('role', 'administrator')
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
})
|
||||
}}
|
||||
disabled={formik.values.role === 'administrator'}
|
||||
>
|
||||
Administrador
|
||||
</Button>
|
||||
<Button
|
||||
type='button'
|
||||
onClick={() => {
|
||||
formik.setFieldValue('role', 'collaborator')
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
})
|
||||
}}
|
||||
disabled={formik.values.role === 'collaborator'}
|
||||
>
|
||||
Colaborador
|
||||
</Button>
|
||||
</div>
|
||||
<div
|
||||
className={css({
|
||||
display: 'grid',
|
||||
gridTemplateColumns: { base: '1fr', md: '1fr 1fr' },
|
||||
gap: 'medium'
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className={css({
|
||||
order: { base: 2, md: 1 }
|
||||
})}
|
||||
>
|
||||
<FormGroup>
|
||||
<label htmlFor='name'>Nombre</label>
|
||||
<Input
|
||||
id='name'
|
||||
type='text'
|
||||
value={formik.values.name}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
/>
|
||||
{formik.touched.name !== undefined && formik.errors.name !== undefined && (
|
||||
<Typography variant='caption' color='danger'>
|
||||
{formik.errors.name}
|
||||
</Typography>
|
||||
)}
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<label htmlFor='email'>Email</label>
|
||||
<Input
|
||||
id='email'
|
||||
type='email'
|
||||
value={formik.values.email}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
/>
|
||||
{formik.touched.email !== undefined && formik.errors.email !== undefined && (
|
||||
<Typography variant='caption' color='danger'>
|
||||
{formik.errors.email}
|
||||
</Typography>
|
||||
)}
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<label htmlFor='discordName'>Nombre de Discord</label>
|
||||
<Input
|
||||
id='discordName'
|
||||
type='text'
|
||||
value={formik.values.discordName}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
/>
|
||||
{formik.touched.discordName !== undefined && formik.errors.discordName !== undefined && (
|
||||
<Typography variant='caption' color='danger'>
|
||||
{formik.errors.discordName}
|
||||
</Typography>
|
||||
)}
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<label htmlFor='message'>Mensaje</label>
|
||||
<Input
|
||||
id='message'
|
||||
type='text'
|
||||
value={formik.values.message}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
/>
|
||||
{formik.touched.message !== undefined && formik.errors.message !== undefined && (
|
||||
<Typography variant='caption' color='danger'>
|
||||
{formik.errors.message}
|
||||
</Typography>
|
||||
)}
|
||||
</FormGroup>
|
||||
<Button
|
||||
type='submit'
|
||||
>
|
||||
Enviar
|
||||
</Button>
|
||||
</div>
|
||||
<div
|
||||
className={css({
|
||||
overflow: 'hidden',
|
||||
order: { base: 1, md: 2 },
|
||||
paddingBlock: 'medium'
|
||||
})}
|
||||
>
|
||||
<AnimatePresence mode='wait' initial={false}>
|
||||
{formik.values.role === 'moderator' && (
|
||||
<motion.div
|
||||
key={'motion-moderator'}
|
||||
transition={{ duration: 0.15, ease: 'easeInOut' }}
|
||||
initial={{ opacity: 0, x: '-250px' }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
exit={{ opacity: 0, x: '250px' }}
|
||||
>
|
||||
<Typography variant='h2' align="center">Moderadores</Typography>
|
||||
<Typography variant='body1'>
|
||||
El equipo de moderación de EntGamers se encarga de moderar los distintos espacios en los que se desenvuelve la comunidad, como los grupos de Facebook, Discord, Etc.
|
||||
</Typography>
|
||||
<Typography variant='h3'>Requisitos</Typography>
|
||||
<ul className="fa-ul">
|
||||
<li>
|
||||
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Imparcialidad</strong>
|
||||
<br />
|
||||
La comunidad esta conformada por amigos y conocidos, por lo tanto es importante poder actuar de forma imparcial y responsable.
|
||||
</li>
|
||||
</ul>
|
||||
<Typography variant='h3'>Beneficios</Typography>
|
||||
<ul className="fa-ul">
|
||||
<li>
|
||||
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Experiencia</strong>
|
||||
<br />
|
||||
Uno de los objetivos de la comunidad es brindar experiencia en gestión y desarrollo de proyectos equiparable a un entorno laboral, que sea comprobable y útil.
|
||||
</li>
|
||||
</ul>
|
||||
</motion.div>
|
||||
)}
|
||||
{formik.values.role === 'collaborator' && (
|
||||
<motion.div
|
||||
key={'motion-collaborator'}
|
||||
transition={{ duration: 0.15, ease: 'easeInOut' }}
|
||||
initial={{ opacity: 0, x: '-250px' }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
exit={{ opacity: 0, x: '250px' }}
|
||||
>
|
||||
<Typography variant='h2' align='center'>Colaborador</Typography>
|
||||
<Typography variant='body1'>
|
||||
Los colaboradores son personas ajenas al staff central de EntGamers que nos ayudan a traer contenido, eventos y actividades a la comunidad.
|
||||
</Typography>
|
||||
<Typography variant='h3'>Requisitos</Typography>
|
||||
<ul className="fa-ul">
|
||||
<li>
|
||||
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Profesionalismo</strong>
|
||||
<br />
|
||||
La comunidad siempre intenta conseguir el mayor nivel de calidad en todos sus proyectos, por lo que buscamos gente dispuesta a otorgar este nivel de profesionalismo para el disfrute de la comunidad.
|
||||
</li>
|
||||
</ul>
|
||||
<Typography variant='h3'>Beneficios</Typography>
|
||||
<ul className="fa-ul">
|
||||
<li>
|
||||
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Apoyo</strong>
|
||||
<br />
|
||||
Puedes contar con el apoyo de la comunidad para tus proyectos, ya sea en forma de difusión, asesoramiento o recursos.
|
||||
</li>
|
||||
</ul>
|
||||
</motion.div>
|
||||
)}
|
||||
{formik.values.role === 'administrator' && (
|
||||
<motion.div
|
||||
key={'motion-administrator'}
|
||||
transition={{ duration: 0.15, ease: 'easeInOut' }}
|
||||
initial={{ opacity: 0, x: '-250px' }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
exit={{ opacity: 0, x: '250px' }}
|
||||
>
|
||||
<Typography variant='h2' align='center'>Administradores</Typography>
|
||||
<Typography variant='body1'>
|
||||
Los administradores son quienes se encargan de que todo funcione como es debido en la comunidad, desde la moderación de los grupos hasta la organización de eventos y actividades. Son los responsables de que la comunidad siga creciendo y mejorando.
|
||||
</Typography>
|
||||
<Typography variant='h3'>Requisitos</Typography>
|
||||
<ul className="fa-ul">
|
||||
<li>
|
||||
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Profesionalismo</strong>
|
||||
<br />
|
||||
La comunidad siempre intenta conseguir el mayor nivel de calidad en todos sus proyectos, por lo que buscamos gente dispuesta a otorgar este nivel de profesionalismo para el disfrute de la comunidad.
|
||||
</li>
|
||||
<li>
|
||||
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Constancia</strong>
|
||||
<br />
|
||||
La comunidad busca gente que en sus posibilidades sea activa, que pueda estar al tanto de lo que pasa en ella.
|
||||
</li>
|
||||
<li>
|
||||
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Proactividad</strong>
|
||||
<br />
|
||||
La comunidad esta en constante crecimiento, por eso, buscamos gente que ayude a buscar nuevas oportunidades para diferentes proyectos y actividades de interés a la comunidad.
|
||||
</li>
|
||||
</ul>
|
||||
<Typography variant='h3'>Beneficios</Typography>
|
||||
<ul className="fa-ul">
|
||||
<li>
|
||||
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Experiencia</strong>
|
||||
<br />
|
||||
Uno de los objetivos de la comunidad es brindar experiencia en gestión y desarrollo de proyectos equiparable a un entorno laboral, que sea comprobable y útil.
|
||||
</li>
|
||||
<li>
|
||||
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Capacitación</strong>
|
||||
<br />
|
||||
La comunidad buscara dar capacitación a sus miembros en lo referido a herramientas y procedimientos utilizados.
|
||||
</li>
|
||||
<li></li>
|
||||
</ul>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
export default ApplyForm
|
||||
@@ -1,7 +1,7 @@
|
||||
import Typography from '@/components/ui/Typography'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { Container } from '@/styled-system/jsx'
|
||||
import { type FC } from 'react'
|
||||
import ApplyForm from './ApplyForm'
|
||||
|
||||
const EquipoUnirsePage: FC = () => {
|
||||
return (
|
||||
@@ -10,21 +10,7 @@ const EquipoUnirsePage: FC = () => {
|
||||
<Typography variant="body1">
|
||||
El equipo de EntGamers está formado por personas que se dedican a la administración de la comunidad, a la organización de eventos y a la creación de contenido. Aquí podrás enterarte cuales son las funciones de cada uno de los miembros del equipo y como puedes unirte a nosotros.
|
||||
</Typography>
|
||||
<div
|
||||
className={css({
|
||||
backgroundColor: 'info',
|
||||
color: 'info.contrast',
|
||||
borderRadius: 'medium',
|
||||
padding: 'medium',
|
||||
marginBlock: 'medium',
|
||||
'& a': {
|
||||
color: 'info.contrast',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
})}
|
||||
>
|
||||
Esta sección está en construcción. Puedes unirte contactándonos mediante nuestro <a href="http://discord.gg/nqwzHJC">Servidor de Discord</a>.
|
||||
</div>
|
||||
<ApplyForm />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
+9
-1
@@ -2,9 +2,17 @@ import Clanes from '@/app/Clanes'
|
||||
import Hero from '@/app/Hero'
|
||||
import Social from '@/app/Social'
|
||||
import Team from '@/app/Team'
|
||||
import { ensureRoles } from '@/services/backend/roles'
|
||||
import { ensureTeamApplyCollection } from '@/services/backend/teamApply'
|
||||
import { type FC } from 'react'
|
||||
|
||||
const HomePage: FC = () => {
|
||||
const ensureAll = async (): Promise<void> => {
|
||||
await ensureRoles()
|
||||
await ensureTeamApplyCollection()
|
||||
}
|
||||
|
||||
const HomePage: FC = async () => {
|
||||
await ensureAll()
|
||||
return (
|
||||
<>
|
||||
<Hero />
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import trees from '@/assets/icons/trees'
|
||||
import BackDrop from '@/components/ui/BackDrop'
|
||||
import IconButton from '@/components/ui/IconButton'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { iconButton } from '@/styled-system/recipes'
|
||||
import { type IconDefinition } from '@fortawesome/fontawesome-common-types'
|
||||
@@ -29,14 +30,11 @@ const Menu: FC = () => {
|
||||
}, [])
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className={iconButton({
|
||||
color: 'primary'
|
||||
})}
|
||||
<IconButton
|
||||
onClick={() => { setIsMenuOpen(!isMenuOpen) }}
|
||||
>
|
||||
<FontAwesomeIcon icon={faBars} />
|
||||
</button>
|
||||
</IconButton>
|
||||
<BackDrop
|
||||
onClickAway={handleClickAway}
|
||||
isOpen={isMenuOpen}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { cx } from '@/styled-system/css'
|
||||
import { button, type ButtonVariantProps } from '@/styled-system/recipes/button'
|
||||
import { type MergeOmitting } from '@/types/utilities'
|
||||
import { type ButtonHTMLAttributes, type DetailedHTMLProps, type FC } from 'react'
|
||||
|
||||
type ComposedButtonProps = MergeOmitting<DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, ButtonVariantProps>
|
||||
|
||||
export interface ButtonProps extends ComposedButtonProps {}
|
||||
|
||||
const Button: FC<ButtonProps> = ({ children, className, ...rest }) => {
|
||||
const [buttonRecipeArgs, allOtherButtonProps] = button.splitVariantProps(rest)
|
||||
return (
|
||||
<button
|
||||
className={cx(button(buttonRecipeArgs), className)}
|
||||
{...allOtherButtonProps}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
export default Button
|
||||
@@ -0,0 +1,22 @@
|
||||
import { cx } from '@/styled-system/css'
|
||||
import { iconButton, type IconButtonVariantProps } from '@/styled-system/recipes/icon-button'
|
||||
import { type MergeOmitting } from '@/types/utilities'
|
||||
import React, { type FC } from 'react'
|
||||
|
||||
type ComposedIconButtonProps = MergeOmitting<React.HTMLAttributes<HTMLButtonElement>, IconButtonVariantProps>
|
||||
|
||||
export interface IconButtonProps extends ComposedIconButtonProps {}
|
||||
|
||||
const IconButton: FC<IconButtonProps> = ({ children, className, ...rest }) => {
|
||||
const [iconButtonRecipeArgs, allOtherIconButtonProps] = iconButton.splitVariantProps(rest)
|
||||
return (
|
||||
<button
|
||||
className={cx(iconButton(iconButtonRecipeArgs), className)}
|
||||
{...allOtherIconButtonProps}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
export default IconButton
|
||||
@@ -0,0 +1,23 @@
|
||||
import { css, cx } from '@/styled-system/css'
|
||||
import { type DetailedHTMLProps, type FC, type HTMLAttributes, type ReactNode } from 'react'
|
||||
|
||||
export interface FormGroupProps extends DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
const FormGroup: FC<FormGroupProps> = ({ children, className, ...props }) => {
|
||||
return (
|
||||
<div
|
||||
className={cx(css({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 'small',
|
||||
paddingBlock: 'small'
|
||||
}), className)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default FormGroup
|
||||
@@ -0,0 +1,17 @@
|
||||
import { cx } from '@/styled-system/css'
|
||||
import { input, type InputVariantProps } from '@/styled-system/recipes/input'
|
||||
import { type MergeOmitting } from '@/types/utilities'
|
||||
import { type DetailedHTMLProps, type FC, type InputHTMLAttributes } from 'react'
|
||||
|
||||
export type InputProps = MergeOmitting<DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, InputVariantProps>
|
||||
|
||||
const Input: FC<InputProps> = ({ className, ...props }) => {
|
||||
const [inputCss, rest] = input.splitVariantProps(props)
|
||||
return (
|
||||
<input
|
||||
className={cx(input(inputCss), className)}
|
||||
{...rest}
|
||||
/>
|
||||
)
|
||||
}
|
||||
export default Input
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Client, Databases } from 'appwrite'
|
||||
|
||||
export const appwriteClient = new Client()
|
||||
.setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT ?? '')
|
||||
.setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT ?? '')
|
||||
|
||||
export const databases = new Databases(appwriteClient)
|
||||
|
||||
export { ID } from 'appwrite'
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Client, Databases, Teams } from 'node-appwrite'
|
||||
|
||||
export const clientNodeAppwrite = new Client()
|
||||
.setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT ?? '')
|
||||
.setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID ?? '')
|
||||
.setKey(process.env.APPWRITE_API_KEY ?? '')
|
||||
|
||||
export const databases = new Databases(clientNodeAppwrite)
|
||||
|
||||
export const teams = new Teams(clientNodeAppwrite)
|
||||
|
||||
export { Permission, Role } from 'node-appwrite'
|
||||
@@ -0,0 +1,18 @@
|
||||
import { databases } from '@/lib/nodeAppwrite'
|
||||
|
||||
export const DATABASE_NAME = 'entgamers-website'
|
||||
export const DATABASE_ID = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID ?? DATABASE_NAME
|
||||
|
||||
export const ensureDatabase = (() => {
|
||||
let databaseEnsured = false
|
||||
return async () => {
|
||||
if (databaseEnsured) return
|
||||
try {
|
||||
await databases.get(DATABASE_ID)
|
||||
} catch (error) {
|
||||
await databases.create(DATABASE_ID, DATABASE_NAME)
|
||||
} finally {
|
||||
databaseEnsured = true
|
||||
}
|
||||
}
|
||||
})()
|
||||
@@ -0,0 +1,35 @@
|
||||
import { teams } from '@/lib/nodeAppwrite'
|
||||
import { type UserPreferences } from '@/types/User'
|
||||
|
||||
export const ADMIN_TEAM_NAME = 'admin'
|
||||
export const ADMIN_TEAM_ID = process.env.NEXT_PUBLIC_APPWRITE_ADMIN_TEAM_ID ?? ADMIN_TEAM_NAME
|
||||
export const MODERATOR_TEAM_NAME = 'moderator'
|
||||
export const MODERATOR_TEAM_ID = process.env.NEXT_PUBLIC_APPWRITE_MODERATOR_TEAM_ID ?? MODERATOR_TEAM_NAME
|
||||
export const COLLABORATOR_TEAM_NAME = 'collaborator'
|
||||
export const COLLABORATOR_TEAM_ID = process.env.NEXT_PUBLIC_APPWRITE_COLLABORATOR_TEAM_ID ?? COLLABORATOR_TEAM_NAME
|
||||
|
||||
const ensureRoleExists = (roleId: string, roleName: string): (() => Promise<void>) => {
|
||||
let roleExists = false
|
||||
return async (): Promise<void> => {
|
||||
if (roleExists) return
|
||||
try {
|
||||
await teams.get<UserPreferences>(roleId)
|
||||
roleExists = true
|
||||
} catch (error) {
|
||||
await teams.create(roleId, roleName)
|
||||
roleExists = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const ensureRoles = async (): Promise<void> => {
|
||||
const adminRole = ensureRoleExists(ADMIN_TEAM_ID, ADMIN_TEAM_NAME)
|
||||
const moderatorRole = ensureRoleExists(MODERATOR_TEAM_ID, MODERATOR_TEAM_NAME)
|
||||
const collaboratorRole = ensureRoleExists(COLLABORATOR_TEAM_ID, COLLABORATOR_TEAM_NAME)
|
||||
|
||||
await Promise.all([
|
||||
adminRole(),
|
||||
moderatorRole(),
|
||||
collaboratorRole()
|
||||
])
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { Permission, Role, databases } from '@/lib/nodeAppwrite'
|
||||
import { DATABASE_ID, ensureDatabase } from '@/services/backend/database'
|
||||
import { ADMIN_TEAM_ID } from './roles'
|
||||
|
||||
export const TEAM_APPLY_COLLECTION_NAME = 'team-apply'
|
||||
export const TEAM_APPLY_COLLECTION_ID = process.env.NEXT_PUBLIC_APPWRITE_TEAM_APPLY_COLLECTION_ID ?? TEAM_APPLY_COLLECTION_NAME
|
||||
|
||||
export const ensureTeamApplyCollection = (() => {
|
||||
let collectionEnsured = false
|
||||
return async () => {
|
||||
if (collectionEnsured) return
|
||||
await ensureDatabase()
|
||||
try {
|
||||
await databases.getCollection(DATABASE_ID, TEAM_APPLY_COLLECTION_ID)
|
||||
} catch (error) {
|
||||
const permissions = [
|
||||
Permission.create(Role.any()),
|
||||
Permission.read(Role.team(ADMIN_TEAM_ID)),
|
||||
Permission.update(Role.team(ADMIN_TEAM_ID)),
|
||||
Permission.delete(Role.team(ADMIN_TEAM_ID))
|
||||
]
|
||||
await databases.createCollection(DATABASE_ID, TEAM_APPLY_COLLECTION_ID, TEAM_APPLY_COLLECTION_NAME, permissions, false, true)
|
||||
await databases.createStringAttribute(DATABASE_ID, TEAM_APPLY_COLLECTION_ID, 'name', 128, true)
|
||||
await databases.createEmailAttribute(DATABASE_ID, TEAM_APPLY_COLLECTION_ID, 'email', true)
|
||||
await databases.createStringAttribute(DATABASE_ID, TEAM_APPLY_COLLECTION_ID, 'discordName', 128, true)
|
||||
await databases.createStringAttribute(DATABASE_ID, TEAM_APPLY_COLLECTION_ID, 'role', 24, true)
|
||||
await databases.createStringAttribute(DATABASE_ID, TEAM_APPLY_COLLECTION_ID, 'message', 4096, true)
|
||||
} finally {
|
||||
collectionEnsured = true
|
||||
}
|
||||
}
|
||||
})()
|
||||
@@ -0,0 +1,2 @@
|
||||
export const DATABASE_NAME = 'entgamers-website'
|
||||
export const DATABASE_ID = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID ?? DATABASE_NAME
|
||||
@@ -0,0 +1,25 @@
|
||||
import { ID, databases } from '@/lib/appwrite'
|
||||
import { DATABASE_ID } from '@/services/frontend/database'
|
||||
import { type TeamApplyData, type TeamApplyDocument, type TeamApplyList } from '@/types/teamApply'
|
||||
|
||||
export const TEAM_APPLY_COLLECTION_NAME = 'team-apply'
|
||||
export const TEAM_APPLY_COLLECTION_ID = process.env.NEXT_PUBLIC_APPWRITE_TEAM_APPLY_COLLECTION_ID ?? TEAM_APPLY_COLLECTION_NAME
|
||||
|
||||
export const createTeamApply = async (data: TeamApplyData): Promise<TeamApplyDocument> => {
|
||||
const createdTeamApply = await databases.createDocument<TeamApplyDocument>(DATABASE_ID, TEAM_APPLY_COLLECTION_ID, ID.unique(), data)
|
||||
return createdTeamApply
|
||||
}
|
||||
|
||||
export const getTeamApply = async (teamApplyId: string): Promise<TeamApplyDocument> => {
|
||||
const teamApply = await databases.getDocument<TeamApplyDocument>(DATABASE_ID, TEAM_APPLY_COLLECTION_ID, teamApplyId)
|
||||
return teamApply
|
||||
}
|
||||
|
||||
export const listTeamApply = async (): Promise<TeamApplyList> => {
|
||||
const teamApplyList = await databases.listDocuments<TeamApplyDocument>(DATABASE_ID, TEAM_APPLY_COLLECTION_ID)
|
||||
return teamApplyList
|
||||
}
|
||||
|
||||
export const deleteTeamApply = async (teamApplyId: string): Promise<void> => {
|
||||
await databases.deleteDocument(DATABASE_ID, TEAM_APPLY_COLLECTION_ID, teamApplyId)
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
import { type IconDefinition } from '@fortawesome/fontawesome-svg-core'
|
||||
|
||||
export type UserPreferences = Record<string, string>
|
||||
|
||||
export interface TeamMember {
|
||||
image: string
|
||||
name: string
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { type Models } from 'appwrite'
|
||||
|
||||
export interface TeamApplyData {
|
||||
name: string
|
||||
email: string
|
||||
discordName: string
|
||||
message: string
|
||||
role: 'moderator' | 'administrator' | 'collaborator'
|
||||
}
|
||||
|
||||
export type TeamApplyDocument = Models.Document & TeamApplyData
|
||||
|
||||
export type TeamApplyList = Models.DocumentList<TeamApplyDocument>
|
||||
Reference in New Issue
Block a user