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

Fix ticket interface for sellers #665

Merged
merged 22 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
242f994
Fix ticket interface for sellers.
julianweng Apr 17, 2024
e432d2e
Clarify type for buyersPerm.
julianweng Apr 18, 2024
c563536
Merge branch 'ticketing' into ticketing-seller-management
julianweng Apr 21, 2024
22c8035
Merge branch 'ticketing' into ticketing-seller-management
joyliu-q Apr 23, 2024
03c60e7
:art: Yay
joyliu-q Apr 23, 2024
d81183c
Frontend for admin ticket transfering and base props fix.
julianweng Apr 23, 2024
5594ffe
:tada: Add issue ticket
joyliu-q Apr 23, 2024
9e97e05
Frontend for marking tickets as attended/not attended
julianweng Apr 23, 2024
7e23e86
:art: Split String and handle input edge case
joyliu-q Apr 23, 2024
32cf3bd
:broom: Hehe
joyliu-q Apr 23, 2024
2029bd1
:rotating_light: Some changes with a fake api endpoint
joyliu-q Apr 24, 2024
e917d5f
:tada: Some fire UI
joyliu-q Apr 24, 2024
263137a
:bug: Error Response not showing correctly
joyliu-q Apr 24, 2024
ae039fb
:art: Brr
joyliu-q Apr 25, 2024
15a6231
Lint, improve UI language, fix items remaining in cart after deletion…
julianweng Apr 25, 2024
a8a4e26
Merge branch 'ticketing' into ticketing-seller-management
julianweng Apr 25, 2024
dbc7bba
API integration for issuing tickets
julianweng Apr 25, 2024
d5e1eae
Ticket transfer interface
julianweng Apr 25, 2024
445fdd2
Merge branch 'ticketing' into ticketing-seller-management
julianweng Apr 25, 2024
1b3a78e
Integrate attendance into frontend and add warning popup for un-atten…
julianweng Apr 25, 2024
22cda9a
:art: Nit
joyliu-q Apr 26, 2024
e485935
:bug: Joy fixes everything
joyliu-q Apr 26, 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
6 changes: 4 additions & 2 deletions backend/clubs/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2540,14 +2540,16 @@ def buyers(self, request, *args, **kwargs):
type: integer
type:
type: string
attended:
type: boolean
---
"""
tickets = Ticket.objects.filter(event=self.get_object()).annotate(
fullname=Concat("owner__first_name", Value(" "), "owner__last_name")
)

buyers = tickets.filter(owner__isnull=False).values(
"fullname", "id", "owner_id", "type", "owner__email"
"fullname", "id", "owner_id", "type", "attended", "owner__email"
)

return Response({"buyers": buyers})
Expand Down Expand Up @@ -5031,7 +5033,7 @@ def partial_update(self, request, *args, **kwargs):
schema:
type: object
properties:
attendance:
attended:
type: boolean
responses:
"200":
Expand Down
6 changes: 1 addition & 5 deletions frontend/components/ClubEditPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -291,11 +291,7 @@ const ClubForm = ({
{
name: 'tickets',
label: 'Tickets',
content: (
<>
<TicketsViewCard club={club} />
</>
),
content: <TicketsViewCard club={club} />,
},
{
name: 'recruitment',
Expand Down
5 changes: 4 additions & 1 deletion frontend/components/ClubEditPage/EventsImportCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { doApiRequest } from '../../utils'
import { Contact, Icon, Text } from '../common'
import { TextField } from '../FormComponents'
import BaseCard from './BaseCard'
import { WHITE } from '~/constants'

type EventsImportCardProps = {
club: Club
Expand All @@ -29,7 +30,9 @@ export default function EventsImportCard({
onFetchEvents && onFetchEvents()
})
.catch(() => {
toast.error('Failed to fetch events, an unknown error occured.')
toast.error('Failed to fetch events, an unknown error occured.', {
style: { color: WHITE },
})
})
.finally(() => setFetching(false))
}
Expand Down
37 changes: 15 additions & 22 deletions frontend/components/ClubEditPage/TicketsViewCard.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,31 @@
import Link from 'next/link'
import React, { ReactElement } from 'react'

import { doApiRequest } from '~/utils'
import { Club } from '~/types'

import Table from '../common/Table'
import BaseCard from './BaseCard'

export default function TicketsViewCard({ club }): ReactElement {
const GetTicketsHolders = (id) => {
doApiRequest(`/events/${id}/tickets?format=json`, {
method: 'GET',
})
.then((resp) => resp.json())
.then((res) => {
// console.log(res)
})
}

export default function TicketsViewCard({
club,
}: {
club: Club
}): ReactElement {
const eventsTableFields = [
{ label: 'Event Name', name: 'name' },
{
label: '',
name: 'view',
render: (id) => (
<button className="button is-primary is-pulled-right">
<Link href={'/tickets/' + id}>
<a style={{ color: 'white' }} target="blank">
View
</a>
<Link style={{ color: 'white' }} href={`/tickets/${id}`}>
View
</Link>
</button>
),
},
]

// console.log(club.events)
const ticketEvents = club.events.filter((event) => event.ticketed)

return (
Expand All @@ -47,14 +38,16 @@ export default function TicketsViewCard({ club }): ReactElement {
columns={eventsTableFields}
searchableColumns={['name']}
filterOptions={[]}
hideSearch={true}
focusable={true}
hideSearch
focusable
/>
) : (
<>
You don't have any ticketed events, to add create ticketed events or
add ticket offerings, to existing events, go to the events, click
create on the tickets section below the event details.
You don't have any ticketed events. To create a ticketed event or add
ticket offerings to existing events, go to{' '}
<Link href={`/club/${club.code}/edit/events`}>Events</Link> within
this dashboard and click "Create" in the tickets section below event
details.
</>
)}
</BaseCard>
Expand Down
5 changes: 4 additions & 1 deletion frontend/components/EventPage/SyncModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { ReactElement, useEffect, useState } from 'react'
import { toast } from 'react-toastify'
import styled from 'styled-components'

import { CLUBS_GREY, CLUBS_NAVY } from '../../constants'
import { CLUBS_GREY, CLUBS_NAVY, WHITE } from '../../constants'
import { Club } from '../../types'
import { doApiRequest, intersperse } from '../../utils'
import {
Expand Down Expand Up @@ -80,6 +80,9 @@ const SyncModal = (): ReactElement | null => {
} catch (error) {
toast.error(
'Failed to copy! You need to manually copy the URL.',
{
style: { color: WHITE },
},
)
}
}}
Expand Down
6 changes: 5 additions & 1 deletion frontend/components/Settings/BulkEditTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { Icon, Text } from '../common'
import { DateTimeField, SelectField, TextField } from '../FormComponents'
import { fixDeserialize } from '../reports/ReportForm'
import { WHITE } from '~/constants'

/**
* A component where the user can enter a list of club names and get a list of club codes in response.
Expand Down Expand Up @@ -78,7 +79,10 @@ const BulkEditTab = ({ tags, clubfairs, badges }: BulkEditTabProps) => {
if (contents.message) {
toast.info(contents.message, { hideProgressBar: true })
} else if (contents.error) {
toast.error(contents.error, { hideProgressBar: true })
toast.error(contents.error, {
hideProgressBar: true,
style: { color: WHITE },
})
}
} finally {
setSubmitting(false)
Expand Down
123 changes: 52 additions & 71 deletions frontend/components/Settings/TicketTransferModal.tsx
Original file line number Diff line number Diff line change
@@ -1,84 +1,65 @@
import React, { ReactElement, useEffect, useState } from 'react'
import { toast, TypeOptions } from 'react-toastify'
import styled from 'styled-components'
import { ReactElement, useEffect, useState } from 'react'

import {
ALLBIRDS_GRAY,
CLUBS_GREY,
FOCUS_GRAY,
WHITE,
} from '../../constants/colors'
import { BORDER_RADIUS } from '../../constants/measurements'
import { BODY_FONT } from '../../constants/styles'
import { ClubEvent } from '../../types'
import { SearchInput } from '../SearchBar'
import { doApiRequest } from '~/utils'

const ModalContainer = styled.div`
text-align: left;
position: relative;
`
const ModalBody = styled.div`
padding: 2rem;
`
const SectionContainer = styled.div`
margin-bottom: 1.5rem;
`
import BaseCard from '../ClubEditPage/BaseCard'

const Input = styled.input`
border: 1px solid ${ALLBIRDS_GRAY};
outline: none;
color: ${CLUBS_GREY};
width: 100%;
font-size: 1em;
padding: 8px 10px;
margin: 0px 5px 0px 0px;
background: ${WHITE};
border-radius: ${BORDER_RADIUS};
font-family: ${BODY_FONT};
&:hover,
&:active,
&:focus {
background: ${FOCUS_GRAY};
}
`

const notify = (
msg: ReactElement | string,
type: TypeOptions = 'info',
): void => {
toast[type](msg)
type TicketTransferModalProps = {
id: string
onSuccessfulTransfer: (id: string) => void
}

const TicketTransferModal = (props: {
event: ClubEvent | null
}): ReactElement => {
const [searchInput, setSearchInput] = useState<SearchInput>({})
const TicketTransferModal = ({
id,
onSuccessfulTransfer,
}: TicketTransferModalProps): ReactElement => {
const [recipient, setRecipient] = useState<string | undefined>()
const [recipientError, setRecipientError] = useState<string | undefined>()

const search = () => {
/*
return doApiRequest('/users?search=bfranklin')
.then((resp) => resp.json())
.then(() => {})
*/
}
useEffect(() => {
search()
}, [])
/*
<CoverPhoto
image={large_image_url ?? image_url}
fallback={
<p>{club_name != null ? club_name.toLocaleUpperCase() : 'Event'}</p>
}
/>
setRecipientError(undefined)
}, [id])

<Title>{name}</Title>
*/
function transferTicket() {
if (!recipient) {
setRecipientError('Recipient PennKey is required')
return
}
setRecipientError(undefined)
doApiRequest(`/tickets/${id}/transfer/?format=json`, {
method: 'POST',
body: { username: recipient },
}).then(async (resp) => {
if (resp.ok) {
onSuccessfulTransfer(id)
} else {
setRecipientError((await resp.json()).detail)
}
})
}

return (
<ModalContainer>
<ModalBody></ModalBody>
</ModalContainer>
<BaseCard title="Ticket Transfer">
<input
className="input"
value={recipient}
onChange={(e) => setRecipient(e.target.value)}
onKeyUp={(e) => {
if (e.key === 'Enter') {
transferTicket()
}
}}
placeholder="Recipient PennKey"
/>
{recipientError && <p className="has-text-danger">{recipientError}</p>}
<button
className="button is-success"
onClick={transferTicket}
style={{ marginTop: '15px' }}
>
Transfer Ticket
</button>
</BaseCard>
)
}

Expand Down
Loading
Loading