feat: static equipo unirse

This commit is contained in:
2024-01-03 15:03:08 -06:00
parent ba466dfd80
commit b393e0cdb0
8 changed files with 278 additions and 144 deletions
BIN
View File
Binary file not shown.
+8 -10
View File
@@ -11,25 +11,23 @@
"prepare": "panda codegen && husky install" "prepare": "panda codegen && husky install"
}, },
"dependencies": { "dependencies": {
"@fontsource/open-sans": "^5.0.12", "@fontsource/open-sans": "^5.0.20",
"@fontsource/permanent-marker": "^5.0.8", "@fontsource/permanent-marker": "^5.0.8",
"@fortawesome/fontawesome-svg-core": "^6.5.1", "@fortawesome/fontawesome-svg-core": "^6.5.1",
"@fortawesome/free-brands-svg-icons": "^6.5.1", "@fortawesome/free-brands-svg-icons": "^6.5.1",
"@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/free-solid-svg-icons": "^6.5.1",
"@fortawesome/react-fontawesome": "^0.2.0", "@fortawesome/react-fontawesome": "^0.2.0",
"appwrite": "^13.0.0", "appwrite": "^13.0.1",
"entgamers-panda-preset": "0.1.0", "entgamers-panda-preset": "0.1.0",
"formik": "^2.4.4", "formik": "^2.4.5",
"framer-motion": "^10.16.4", "framer-motion": "^10.16.16",
"gsap": "^3.12.2",
"isomorphic-fetch": "^3.0.0", "isomorphic-fetch": "^3.0.0",
"next": "13.4.19", "next": "^14.0.4",
"next-connect": "^1.0.0", "node-appwrite": "^11.1.0",
"node-appwrite": "^11.0.0",
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"sharp": "^0.32.5", "sharp": "^0.33.1",
"yup": "^1.2.0" "yup": "^1.3.3"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^18.4.3", "@commitlint/cli": "^18.4.3",
+14 -27
View File
@@ -1,34 +1,12 @@
import Typography from '@/components/ui/Typography' import Typography from '@/components/ui/Typography'
import { css, cx } from '@/styled-system/css' import { css } from '@/styled-system/css'
import { Container } from '@/styled-system/jsx' import { Container } from '@/styled-system/jsx'
import { center } from '@/styled-system/patterns' import { center } from '@/styled-system/patterns'
import { button, card, iconButton } from '@/styled-system/recipes' import { button } from '@/styled-system/recipes'
import { type TeamMember } from '@/types/User'
import { faFacebook, faInstagram, faTwitch, faTwitter, faYoutube } from '@fortawesome/free-brands-svg-icons'
import { faGlobe } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import NextImage from 'next/image'
import NextLink from 'next/link' import NextLink from 'next/link'
import { type FC } from 'react' import { type FC } from 'react'
const team: TeamMember[] = [ const EquipoPage: FC = async () => {
{
image: '/images/team/SrJuggernaut.png',
name: 'SrJuggernaut',
role: 'administrator',
description: 'Soy desarrollador web y me gusta jugar videojuegos.',
socialNetworks: [
{ url: 'https://www.facebook.com/SrJuggernaut', label: 'SrJuggernaut Facebook', icon: faFacebook },
{ url: 'https://twitter.com/SrJuggernaut', label: 'SrJuggernaut Twitter', icon: faTwitter },
{ url: 'https://youtube.com/juggernautplays', label: 'SrJuggernaut YouTube', icon: faYoutube },
{ url: 'https://twitch.tv/juggernautplays', label: 'SrJuggernaut Twitch', icon: faTwitch },
{ url: 'https://www.instagram.com/sr_juggernaut', label: 'SrJuggernaut Instagram', icon: faInstagram },
{ url: 'https://srjuggernaut.dev/', label: 'SrJuggernaut Website', icon: faGlobe }
]
}
]
const EquipoPage: FC = () => {
return ( return (
<Container> <Container>
<Typography variant="h1" align="center">Equipo</Typography> <Typography variant="h1" align="center">Equipo</Typography>
@@ -49,7 +27,7 @@ const EquipoPage: FC = () => {
flexWrap: 'wrap' flexWrap: 'wrap'
})} })}
> >
{team.map((member, index) => ( {/* {team.map((member, index) => (
<div <div
key={`team-member-${index}`} key={`team-member-${index}`}
className={cx(card({ variant: 'retro' }).body, css({ className={cx(card({ variant: 'retro' }).body, css({
@@ -92,8 +70,17 @@ const EquipoPage: FC = () => {
</div> </div>
</div> </div>
</div> </div>
))} ))} */}
</Container> </Container>
<div className={center()}>
<NextLink
className={button({ color: 'info' })}
href="/equipo/unirse?role=administrator"
>
¡Quiero ser administrador!
</NextLink>
</div>
<Typography variant="h2" align="center">Moderadores</Typography> <Typography variant="h2" align="center">Moderadores</Typography>
<Typography variant="body1"> <Typography variant="body1">
Los moderadores son los encargados de mantener el orden en los grupos de la comunidad, así como de ayudar a los usuarios a resolver sus dudas. Los moderadores son los encargados de mantener el orden en los grupos de la comunidad, así como de ayudar a los usuarios a resolver sus dudas.
+95 -22
View File
@@ -1,19 +1,25 @@
'use client' 'use client'
import Alert from '@/components/ui/Alert'
import Button from '@/components/ui/Button' import Button from '@/components/ui/Button'
import Typography from '@/components/ui/Typography' import Typography from '@/components/ui/Typography'
import FormGroup from '@/components/ui/form/FormGroup' import FormGroup from '@/components/ui/form/FormGroup'
import Input from '@/components/ui/form/Input' import Input from '@/components/ui/form/Input'
import TextArea from '@/components/ui/form/TextArea'
import { createTeamApply } from '@/services/frontend/teamApply'
import { css } from '@/styled-system/css' import { css } from '@/styled-system/css'
import { type Alert as AlertType } from '@/types/feedback'
import { type TeamApplyData } from '@/types/teamApply' import { type TeamApplyData } from '@/types/teamApply'
import { faChevronRight } from '@fortawesome/free-solid-svg-icons' import { faChevronRight } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { FontAwesomeIcon, type FontAwesomeIconProps } from '@fortawesome/react-fontawesome'
import { AppwriteException } from 'appwrite'
import { useFormik } from 'formik' import { useFormik } from 'formik'
import { AnimatePresence, motion } from 'framer-motion' import { AnimatePresence, motion } from 'framer-motion'
import { useSearchParams } from 'next/navigation' import { useSearchParams } from 'next/navigation'
import { useEffect, type FC } from 'react' import { useEffect, useState, type FC } from 'react'
const ApplyForm: FC = () => { const ApplyForm: FC = () => {
const searchParams = useSearchParams() const searchParams = useSearchParams()
const [alert, setAlert] = useState<AlertType | undefined>(undefined)
const formik = useFormik<TeamApplyData>({ const formik = useFormik<TeamApplyData>({
initialValues: { initialValues: {
@@ -23,8 +29,25 @@ const ApplyForm: FC = () => {
message: '', message: '',
role: 'administrator' role: 'administrator'
}, },
onSubmit: (values) => { onSubmit: async (values) => {
console.log(values) try {
await createTeamApply(values)
} catch (error) {
if (error instanceof AppwriteException) {
setAlert({
title: 'Error al enviar el formulario',
message: error.message,
severity: 'error'
})
return
}
console.error('Error al enviar el formulario', error)
setAlert({
severity: 'error',
title: 'Error al enviar el formulario',
message: 'Hubo un error al enviar el formulario, por favor, intenta nuevamente.'
})
}
} }
}) })
useEffect(() => { useEffect(() => {
@@ -92,6 +115,17 @@ const ApplyForm: FC = () => {
gap: 'medium' gap: 'medium'
})} })}
> >
{alert !== undefined && (
<Alert
severity={alert.severity}
>
{alert.title !== undefined && (
<Typography variant='h5' component='div'>{alert.title}</Typography>
)}
{alert.message}
</Alert>
)}
{formik.submitCount > 0 && (
<div <div
className={css({ className={css({
order: { base: 2, md: 1 } order: { base: 2, md: 1 }
@@ -106,10 +140,16 @@ const ApplyForm: FC = () => {
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'>
Tu nombre.
</Typography>
)} )}
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
@@ -121,11 +161,18 @@ const ApplyForm: FC = () => {
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'>
Tu email, para poder contactarte.
</Typography>
)
}
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<label htmlFor='discordName'>Nombre de Discord</label> <label htmlFor='discordName'>Nombre de Discord</label>
@@ -136,33 +183,58 @@ const ApplyForm: FC = () => {
onChange={formik.handleChange} onChange={formik.handleChange}
onBlur={formik.handleBlur} onBlur={formik.handleBlur}
/> />
{formik.touched.discordName !== undefined && formik.errors.discordName !== undefined && ( {formik.touched.discordName !== undefined && formik.errors.discordName !== undefined
? (
<Typography variant='caption' color='danger'> <Typography variant='caption' color='danger'>
{formik.errors.discordName} {formik.errors.discordName}
</Typography> </Typography>
)} )
: (
<Typography variant='caption' color='info'>
Tu nombre de Discord, para poder contactarte.
</Typography>
)
}
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<label htmlFor='message'>Mensaje</label> <label htmlFor='message'>Mensaje</label>
<Input <TextArea
id='message' id='message'
type='text'
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'>
¿Por que te gustaría unirte al equipo?, ¿Que te gustaría hacer?, etc.
</Typography>
)
}
</FormGroup> </FormGroup>
<div
className={css({
paddingBlock: 'medium'
})}
>
<Button <Button
type='submit' type='submit'
disabled={!formik.isValid || !formik.dirty}
fullWidth
> >
Enviar Enviar
</Button> </Button>
</div> </div>
</div>
)
}
<div <div
className={css({ className={css({
overflow: 'hidden', overflow: 'hidden',
@@ -186,7 +258,7 @@ const ApplyForm: FC = () => {
<Typography variant='h3'>Requisitos</Typography> <Typography variant='h3'>Requisitos</Typography>
<ul className="fa-ul"> <ul className="fa-ul">
<li> <li>
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Imparcialidad</strong> <FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <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>
@@ -194,7 +266,7 @@ const ApplyForm: FC = () => {
<Typography variant='h3'>Beneficios</Typography> <Typography variant='h3'>Beneficios</Typography>
<ul className="fa-ul"> <ul className="fa-ul">
<li> <li>
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Experiencia</strong> <FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <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>
@@ -216,7 +288,7 @@ const ApplyForm: FC = () => {
<Typography variant='h3'>Requisitos</Typography> <Typography variant='h3'>Requisitos</Typography>
<ul className="fa-ul"> <ul className="fa-ul">
<li> <li>
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Profesionalismo</strong> <FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <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>
@@ -224,7 +296,7 @@ const ApplyForm: FC = () => {
<Typography variant='h3'>Beneficios</Typography> <Typography variant='h3'>Beneficios</Typography>
<ul className="fa-ul"> <ul className="fa-ul">
<li> <li>
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Apoyo</strong> <FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <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>
@@ -246,17 +318,17 @@ const ApplyForm: FC = () => {
<Typography variant='h3'>Requisitos</Typography> <Typography variant='h3'>Requisitos</Typography>
<ul className="fa-ul"> <ul className="fa-ul">
<li> <li>
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Profesionalismo</strong> <FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <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>
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Constancia</strong> <FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <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>
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Proactividad</strong> <FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <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>
@@ -264,12 +336,12 @@ const ApplyForm: FC = () => {
<Typography variant='h3'>Beneficios</Typography> <Typography variant='h3'>Beneficios</Typography>
<ul className="fa-ul"> <ul className="fa-ul">
<li> <li>
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Experiencia</strong> <FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <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>
<FontAwesomeIcon icon={faChevronRight} fixedWidth listItem /> <strong>Capacitación</strong> <FontAwesomeIcon icon={faChevronRight as FontAwesomeIconProps['icon']} fixedWidth listItem /> <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>
@@ -283,4 +355,5 @@ const ApplyForm: FC = () => {
</form> </form>
) )
} }
export default ApplyForm export default ApplyForm
+36
View File
@@ -0,0 +1,36 @@
import { cx } from '@/styled-system/css'
import { alert, type AlertVariantProps } from '@/styled-system/recipes/alert'
import { type MergeOmitting } from '@/types/utilities'
import { faTimes } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon, type FontAwesomeIconProps } from '@fortawesome/react-fontawesome'
import { type ButtonHTMLAttributes, type DetailedHTMLProps, type FC, type HTMLAttributes } from 'react'
export type AlertProps = MergeOmitting<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, AlertVariantProps>
const Alert: FC<AlertProps> = ({ children, className, ...props }) => {
const [alertArgs, allOtherProps] = alert.splitVariantProps(props)
return (
<div
className={cx(alert(alertArgs).body, className)}
{...allOtherProps}
>
{children}
</div>
)
}
export type AlertCloseButtonProps = MergeOmitting<DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, AlertVariantProps>
export const AlertCloseButton: FC<AlertCloseButtonProps> = ({ children, className, ...props }) => {
const [alertArgs, allOtherProps] = alert.splitVariantProps(props)
return (
<button
className={cx(alert(alertArgs).closeButton, className)}
{...allOtherProps}
>
{children !== undefined ? children : <FontAwesomeIcon icon={faTimes as FontAwesomeIconProps['icon']} fixedWidth />}
</button>
)
}
export default Alert
+5 -2
View File
@@ -13,7 +13,8 @@ const BackDrop: FC<BackDropProps> = ({ isOpen, onClickAway, children }) => {
if (typeof window === 'undefined') return null if (typeof window === 'undefined') return null
return createPortal(( return createPortal((
<AnimatePresence> <AnimatePresence>
{isOpen && ( {isOpen
? (
<motion.div <motion.div
className={css({ className={css({
position: 'fixed', position: 'fixed',
@@ -36,7 +37,9 @@ const BackDrop: FC<BackDropProps> = ({ isOpen, onClickAway, children }) => {
> >
{children} {children}
</motion.div> </motion.div>
)} )
: undefined
}
</AnimatePresence> </AnimatePresence>
), document.body) ), document.body)
} }
+32
View File
@@ -0,0 +1,32 @@
import { css, 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 TextareaHTMLAttributes } from 'react'
export type InputProps = MergeOmitting<DetailedHTMLProps<TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>, InputVariantProps>
const TextArea: FC<InputProps> = ({ className, onChange, ...props }) => {
const [textAreaCss, rest] = input.splitVariantProps(props)
return (
<textarea
className={cx(css({
resize: 'none',
overflow: 'auto'
}), input(textAreaCss), className)}
onChange={(event) => {
if (event.target.value.length > 0) {
event.target.style.height = 'auto'
event.target.style.height = `${event.target.scrollHeight}px`
} else {
event.target.style.height = 'auto'
}
if (onChange !== undefined) {
onChange(event)
}
}}
{...rest}
/>
)
}
export default TextArea
+5
View File
@@ -0,0 +1,5 @@
export interface Alert {
title: string
message: string
severity: 'success' | 'info' | 'warning' | 'error'
}