Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/event tags #337

Merged
merged 26 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
267b419
chore: adds method to create a event tag
JohanHjelsethStorstad Oct 8, 2024
d56663f
chore: adds support for color in event-tag schema
JohanHjelsethStorstad Oct 8, 2024
0e9072c
chore: adds a basic Eventtag component
JohanHjelsethStorstad Oct 8, 2024
4a01b3a
feat: creating event tags now works
JohanHjelsethStorstad Oct 8, 2024
ab73164
feat: adds readEventTag actions and Action hof
JohanHjelsethStorstad Oct 8, 2024
3c24ec5
feat: display all available tags to user
JohanHjelsethStorstad Oct 8, 2024
e0f1bd6
chore: shows create and update tag options only for eligable users
JohanHjelsethStorstad Oct 8, 2024
876e659
fix: must distinguish Session class and object better to be able to r…
JohanHjelsethStorstad Oct 8, 2024
a55fddf
style: linter
JohanHjelsethStorstad Oct 8, 2024
557ec38
chore: fixes minor isssues
JohanHjelsethStorstad Oct 8, 2024
4c39710
chore: better layout in EventTagsAdmin
JohanHjelsethStorstad Oct 8, 2024
9b0dad1
chore: adds basic suport for query params
JohanHjelsethStorstad Oct 8, 2024
a08c0b1
chore: makes the way to work with QueryPrams good
JohanHjelsethStorstad Oct 8, 2024
46dd719
fix: fault in data-validation for getting data into dynamicFields for…
JohanHjelsethStorstad Oct 8, 2024
d439faa
chore: displays the selected tag to the user
JohanHjelsethStorstad Oct 8, 2024
550d907
chore: updates screen schema to reflect new event feats
JohanHjelsethStorstad Oct 8, 2024
99ae4b6
chore: adds ability to add tags to events
JohanHjelsethStorstad Oct 9, 2024
6dbd2db
chore: improves user experience when selecting tags
JohanHjelsethStorstad Oct 9, 2024
d8f9286
fix: skipDuplicates when creating EventTagEvents on update
JohanHjelsethStorstad Oct 9, 2024
54e47d7
feat: displays an events tags to the end user
JohanHjelsethStorstad Oct 9, 2024
5b5569e
chore: adds ability to remove tags in search
JohanHjelsethStorstad Oct 9, 2024
2da145d
chore: makes it easy for a user to select more tags
JohanHjelsethStorstad Oct 9, 2024
a68d711
feat: adds tags functionality to event-archive page
JohanHjelsethStorstad Oct 9, 2024
bd7c130
feat: destroy event tags
JohanHjelsethStorstad Oct 9, 2024
20b5dda
style: lint errors
JohanHjelsethStorstad Oct 9, 2024
639092b
Merge branch 'main' into feat/event-tags
JohanHjelsethStorstad Oct 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions src/actions/Action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { createZodActionError } from './error'
import { safeServerCall } from './safeServerCall'
import { Session } from '@/auth/Session'
import type { SessionMaybeUser } from '@/auth/Session'
import type { ServiceMethod } from '@/services/ServiceTypes'

export function Action<
TypeType,
DetailedType,
Params,
Return,
WantsToOpenTransaction extends boolean,
NoAuther extends boolean
>(serviceMethod: ServiceMethod<
true,
TypeType,
DetailedType,
Params,
Return,
WantsToOpenTransaction,
NoAuther
>) {
return async (params: Params, rawData: FormData) => {
const session = await Session.fromNextAuth()
const parse = serviceMethod.typeValidate(rawData)
if (!parse.success) return createZodActionError(parse)
const data = parse.data
const config: { session: SessionMaybeUser, params: Params, data: DetailedType } = { session, params, data }
return {
...(await safeServerCall(() => serviceMethod.client('NEW').execute(config, { withAuth: true }))),
session: session.toJsObject()
}
}
}

export function ActionNoData<
Params,
Return,
WantsToOpenTransaction extends boolean,
NoAuther extends boolean
>(serviceMethod: ServiceMethod<
false,
never,
never,
Params,
Return,
WantsToOpenTransaction,
NoAuther
>) {
return async (params: Params) => {
const session = await Session.fromNextAuth()
const config: { session: SessionMaybeUser, params: Params, data: unknown } = { session, params, data: {} }
return {
...(await safeServerCall(() => serviceMethod.client('NEW').execute(config, { withAuth: true }))),
session: session.toJsObject()
}
}
}
2 changes: 2 additions & 0 deletions src/actions/events/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import { safeServerCall } from '@/actions/safeServerCall'
import { Session } from '@/auth/Session'

export async function createEventAction(rawData: FormData) {
console.log('createEventAction')
JohanHjelsethStorstad marked this conversation as resolved.
Show resolved Hide resolved
const parse = Events.create.typeValidate(rawData)
if (!parse.success) return createZodActionError(parse)
const data = parse.data
console.log('createEventAction', data)

const session = await Session.fromNextAuth()

Expand Down
17 changes: 3 additions & 14 deletions src/actions/events/read.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,14 @@
'use server'
import { ActionNoData } from '@/actions/Action'
import { safeServerCall } from '@/actions/safeServerCall'
import { Session } from '@/auth/Session'
import { Events } from '@/services/events'
import type { ReadPageInput } from '@/services/paging/Types'
import type { EventArchiveCursor, EventArchiveDetails } from '@/services/events/Types'

export async function readCurrentEvents() {
const session = await Session.fromNextAuth()
return await safeServerCall(() => Events.readCurrent.client('NEW').execute({
params: { tags: null, visibilityFilter: {} }, session,
}))
}
export const readCurrentEventsAction = ActionNoData(Events.readCurrent)

export async function readEvent(params: {order: number, name: string}) {
const session = await Session.fromNextAuth()
return await safeServerCall(() => Events.read.client('NEW').execute({ params, session }))
}

export async function readArchivedEventsPage<const PageSize extends number>(
paging: ReadPageInput<PageSize, EventArchiveCursor, EventArchiveDetails>
) {
const session = await Session.fromNextAuth()
return await safeServerCall(() => Events.readArchivedPage.client('NEW').execute({ session, params: { paging } }))
}
export const readArchivedEventsPage = ActionNoData(Events.readArchivedPage)
5 changes: 5 additions & 0 deletions src/actions/events/tags/create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use server'
import { EventTags } from '@/services/events/tags'
import { Action } from '@/actions/Action'

export const createEventTagAction = Action(EventTags.create)
5 changes: 5 additions & 0 deletions src/actions/events/tags/destroy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use server'
import { ActionNoData } from '@/actions/Action'
import { EventTags } from '@/services/events/tags'

export const destroyEventTagAction = ActionNoData(EventTags.destroy)
6 changes: 6 additions & 0 deletions src/actions/events/tags/read.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
'use server'
import { ActionNoData } from '@/actions/Action'
import { EventTags } from '@/services/events/tags'

export const readEventTagsAction = ActionNoData(EventTags.readAll)
export const readEventTagAction = ActionNoData(EventTags.read)
5 changes: 5 additions & 0 deletions src/actions/events/tags/update.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use server'
import { Action } from '@/actions/Action'
import { EventTags } from '@/services/events/tags'

export const updateEventTagAction = Action(EventTags.update)
17 changes: 14 additions & 3 deletions src/app/_components/Event/EventCard.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,19 @@ $imgHeight: $height / 2.5;
background-color: lighten(ohma.$colors-secondary, 40%);
border-radius: ohma.$cardRounding;
padding: 3em;
h2 {
font-size: ohma.$fonts-xl;
margin: 0.5em 0;
.topInfo {
display: flex;
align-items: center;
gap: 0 1em;
h2 {
font-size: ohma.$fonts-xl;
margin: 0.5em 0;
}
ul {
display: flex;
gap: 0 .3em;
list-style-type: none;
}
}

}
16 changes: 13 additions & 3 deletions src/app/_components/Event/EventCard.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import styles from './EventCard.module.scss'
import SmallEventTag from './SmallEventTag'
import Image from '@/components/Image/Image'
import React from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faCalendar, faUsers } from '@fortawesome/free-solid-svg-icons'
import Link from 'next/link'
import type { EventFilteredWithImage } from '@/services/events/Types'
import type { EventExpanded } from '@/services/events/Types'

type PropTypes = {
event: EventFilteredWithImage
event: EventExpanded
}

export default function EventCard({ event }: PropTypes) {
Expand All @@ -25,7 +26,16 @@ export default function EventCard({ event }: PropTypes) {
/> : <FontAwesomeIcon icon={faCalendar} />
}
</div>
<h2>{event.name}</h2>
<div className={styles.topInfo}>
<h2>{event.name}</h2>
<ul className={styles.tags}>
{event.tags.map(tag => (
<li key={tag.id}>
<SmallEventTag eventTag={tag} />
</li>
))}
</ul>
</div>
<ul>
<li>
<FontAwesomeIcon icon={faCalendar} />
Expand Down
44 changes: 44 additions & 0 deletions src/app/_components/Event/EventTag.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
@use '@/styles/ohma';

.EventTag {
width: 100px;
height: 50px;
padding: .5em;
border-radius: 50px;
position: relative;
display: flex;
align-items: center;
.description {
padding: 1em;
border-radius: 1em;
background-color: ohma.$colors-gray-400;
color: ohma.$colors-black;
position: absolute;
bottom: 0;
left: 50%;
transform: translate(-50%, calc(100% + 10px));
display: none;
&::before {
content: '';
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, -100%);
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid ohma.$colors-gray-400;
border-top: 0;
}
}
.name {
width: 100%;
text-align: center;
overflow: hidden;
}
&:hover {
cursor: pointer;
.description {
display: block;
}
}
}
22 changes: 22 additions & 0 deletions src/app/_components/Event/EventTag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import styles from './EventTag.module.scss'
import type { EventTag } from '@prisma/client'

type PropTypes = {
eventTag: EventTag
}

export default function EventTag({ eventTag }: PropTypes) {
// if background color is too dark color of text should be white
const textColor = (eventTag.colorR * 0.299 + eventTag.colorG * 0.587 + eventTag.colorB * 0.114) > 100 ? 'black' : 'white'
return (
<div className={styles.EventTag} style={{
color: textColor,
backgroundColor: `rgb(${eventTag.colorR}, ${eventTag.colorG}, ${eventTag.colorB})`
}}>
<p className={styles.name}>{eventTag.name}</p>
<p className={styles.description}>
{eventTag.description}
</p>
</div>
)
}
60 changes: 60 additions & 0 deletions src/app/_components/Event/EventTagsAdmin.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
@use '@/styles/ohma';

.EventTagsAdmin {
max-height: 80svh;
.create {
display: flex;
align-items: center;
form {
display: flex;
flex-direction: row wrap;
@include ohma.screenLg {
align-items: center;
justify-content: center;
gap: 1em;
}
@include ohma.screenMobile {
flex-direction: column;
}
}
}
ul {
margin-top: 1em;
display: flex;
flex-flow: row wrap;
gap: 2em;
overflow-y: auto;
overflow-x: visible;
list-style-type: none;
isolation: isolate;
padding-bottom: 5em;
a {
text-decoration: none;
&.selected {
position: relative;
&:hover {
&::after {
content: '✖';
font-size: 4em;
color: ohma.$colors-black;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
}
}
li {
display: flex;
align-items: center;
z-index: 1;
}
li:hover {
z-index: 2;
}
}
.update {
border-bottom: 3px solid ohma.$colors-gray-800;
}
}
Loading
Loading