Show notice when event pending mandatory revision

This commit is contained in:
Amit Jakubowicz 2019-12-02 13:28:09 +01:00
parent 8b6065baf0
commit b84555dcae
11 changed files with 206 additions and 16 deletions

View File

@ -4,7 +4,7 @@
"extensions": {
"endpoints": {
"Default GraphQL Endpoint": {
"url": "https://alpha.quepasaalpujarra.com/graphql",
"url": "http://localhost:4000/graphql",
"headers": {
"user-agent": "JS GraphQL"
},

58
@types/graphql.d.ts vendored
View File

@ -60,6 +60,7 @@ declare namespace GQL {
location: ILocation;
occurrences: Array<IEventOccurrence | null> | null;
owner: IUser;
publishedState: any;
status: any;
tags: Array<IEventTag | null> | null;
time: IEventTime;
@ -72,6 +73,7 @@ declare namespace GQL {
interface IEventImages {
__typename: 'EventImages';
cover: IEventImage | null;
event: ICalendarEvent | null;
gallery: Array<IEventImage> | null;
poster: IEventImage | null;
thumb: IEventImage | null;
@ -170,13 +172,17 @@ declare namespace GQL {
createEventTag: IEventTag | null;
deleteEvent: IUser;
deleteEventTag: Array<IEventTag | null> | null;
dismissOpenEventRevision: IEventRevision | null;
grantRole: IUser;
removeEventGalleryImages: ICalendarEvent | null;
requestEventRevision: ICalendarEvent | null;
requestInvite: boolean;
revokeRole: IUser;
setEventImage: ICalendarEvent | null;
signin: IUserSession;
signup: Array<IError | null> | null;
startEventRevision: IEventRevision | null;
submitEventRevision: IEventRevision | null;
unsetEventImage: ICalendarEvent | null;
updateEvent: ICalendarEvent | null;
updateEventTag: IEventTag | null;
@ -202,6 +208,10 @@ declare namespace GQL {
input: IDeleteEventTagInput;
}
interface IDismissOpenEventRevisionOnMutationArguments {
input: IEventRevisionInput;
}
interface IGrantRoleOnMutationArguments {
input: IGrantRoleInput;
}
@ -210,6 +220,10 @@ declare namespace GQL {
input: IEventGalleryImagesInput;
}
interface IRequestEventRevisionOnMutationArguments {
input: IRequestRevisionInput;
}
interface IRequestInviteOnMutationArguments {
input: IRequestInviteInput;
}
@ -230,6 +244,14 @@ declare namespace GQL {
input: ISignupInput;
}
interface IStartEventRevisionOnMutationArguments {
input: IStartEventRevisionInput;
}
interface ISubmitEventRevisionOnMutationArguments {
input: IReviseEventInput;
}
interface IUnsetEventImageOnMutationArguments {
id: IUnsetEventImageInput;
}
@ -250,7 +272,7 @@ declare namespace GQL {
interface ICreateEventInput {
infos: Array<IEventInformationInput | null>;
location: IEventLocationInput;
status: string;
publishedState: any;
tagNames: Array<string>;
time: IEventTimeInput;
}
@ -288,6 +310,23 @@ declare namespace GQL {
id: string;
}
interface IEventRevisionInput {
revisionId: string;
}
interface IEventRevision {
__typename: 'EventRevision';
accepting: boolean | null;
author: IUser;
comment: string | null;
createdAt: any;
denying: boolean | null;
event: ICalendarEvent;
id: string;
spam: boolean | null;
submittedAt: any | null;
}
interface IGrantRoleInput {
roleType: any;
userId: string;
@ -298,6 +337,10 @@ declare namespace GQL {
imageIds: Array<string>;
}
interface IRequestRevisionInput {
eventId: string;
}
interface IRequestInviteInput {
email: string;
}
@ -332,6 +375,18 @@ declare namespace GQL {
path: string;
}
interface IStartEventRevisionInput {
eventId: string;
}
interface IReviseEventInput {
accepting: boolean;
comment?: string | null;
denying: boolean;
revisionId: string;
spam: boolean;
}
interface IUnsetEventImageInput {
eventId: string;
imageType?: any | null;
@ -341,6 +396,7 @@ declare namespace GQL {
id: string;
infos?: Array<IEventInformationInput> | null;
location?: IEventLocationInput | null;
publishedState: any;
status?: string | null;
tagNames: Array<string>;
time?: IEventTimeInput | null;

5
@types/index.d.ts vendored
View File

@ -2,3 +2,8 @@ export type EventStatus = "confirmed" | "canceled"
export type EventImageType = "cover" | "thumb" | "gallery" | "poster"
declare module "*.png"
declare module "*.svg"
export enum EventPublishedState {
PUBLISHED = "published",
DRAFT = "draft",
}

View File

@ -1,10 +1,12 @@
{
"en-GB": {
"upload-cover-image": "Upload cover image",
"upload-poster-image": "Upload poster image"
"upload-poster-image": "Upload poster image",
"event-awaiting-mandatory-revision": "This event is pending revision. Our team will soon revise this event and set it online!"
},
"es-ES": {
"upload-cover-image": "Subir imagen de fondo",
"upload-poster-image": "Subir imagen de cartel"
"upload-poster-image": "Subir imagen de cartel",
"event-awaiting-mandatory-revision": "Este evento está pendiente de una revisión. ¡Nuestro equipo revisará este evento pronto y lo publicarémos!"
}
}

View File

@ -1,18 +1,22 @@
import { format } from "date-fns"
import styled, { css } from "qpa-emotion"
import { Button } from "qpa-components"
import styled, { css, useTheme } from "qpa-emotion"
import * as React from "react"
import { hot } from "react-hot-loader"
import intl from "react-intl-universal"
import { RouteComponentProps, withRouter } from "react-router"
import { OccurrenceData } from "../../Event/useOccurrencesQuery"
import EventTags from "../../EventTags/EventTags"
import { useAppContext } from "../Context/AppContext"
import { EventDetailsData } from "./useEventDetailsQuery"
import EventImageUpload from "./EventImageUpload"
import intl from "react-intl-universal"
import messages from "./EventDetails.msg.json"
import EventImageUpload from "./EventImageUpload"
import { EventDetailsData, EventRevisionState } from "./useEventDetailsQuery"
interface Props extends RouteComponentProps {
interface Params {
eventId: string
}
interface Props extends RouteComponentProps<Params> {
event: EventDetailsData
occurrence?: OccurrenceData
}
@ -22,6 +26,7 @@ const EventDetails = (props: Props) => {
const { me, language } = useAppContext()
const event = props.event
const theme = useTheme()
const meIsOwner = me && me.id === event.owner.id
const canEdit =
@ -32,6 +37,16 @@ const EventDetails = (props: Props) => {
event.infos.find(info => info.language === language) || event.infos[0]
return (
<Root>
{event.revisionState ===
EventRevisionState.PENDING_MANDATORY_REVISION && (
<CommentToPublishedState
css={css`
color: ${theme.colors.lead};
`}
>
{intl.get("event-awaiting-mandatory-revision")}
</CommentToPublishedState>
)}
{canEdit ? (
<EditButton
onClick={() => props.history.push(`/event/${event.id}/edit`)}
@ -83,7 +98,6 @@ const EditButton = styled(Button)`
const Title = styled.div`
grid-column: content;
font-size: 32px;
grid-row: 1/1;
`
const Info = styled.div`
@ -128,4 +142,16 @@ const StyledEventTags = styled(EventTags)`
const OccurrenceTime = styled.div`
grid-column: content;
`
const CommentToPublishedState = styled.div`
grid-column: content;
background: rgba(0, 0, 0, 0.2);
border: dashed yellow 2px;
border-radius: 3px;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
padding: 14px;
`
export default hot(module)(withRouter(EventDetails))

View File

@ -0,0 +1,32 @@
import { Spinner } from "qpa-components"
import * as React from "react"
import { RouteComponentProps, withRouter } from "react-router"
import { useAppContext } from "../Context/AppContext"
import EventDetails from "./EventDetails"
import useEventDetailsQuery from "./useEventDetailsQuery"
interface Params {
eventId: string
}
interface Props extends RouteComponentProps<Params> {}
const EventDetailsRoute = (props: Props) => {
const { language } = useAppContext()
const { data, loading, error } = useEventDetailsQuery({
variables: {
eventId: props.match.params.eventId,
language,
},
})
if (loading) {
return <Spinner />
}
if (error) {
return <p>{error.message}</p>
}
return <EventDetails event={data.event} />
}
export default withRouter(EventDetailsRoute)

View File

@ -1,5 +1,6 @@
import { QueryHookOptions, useQuery } from "@apollo/react-hooks"
import gql from "graphql-tag"
import {EventPublishedState} from "../../../../@types"
import {
EventTagTranslatedData,
TranslationDataFragment,
@ -10,6 +11,15 @@ export const EventImageDataFragment = gql`
url,
}
`
export enum EventRevisionState {
PENDING_SUGGESTED_REVISION = "pending_suggested_revision",
PENDING_MANDATORY_REVISION = "pending_mandatory_revision",
CHANGES_REQUIRED = "changes_required",
ACCEPTED = "accepted",
DENIED = "denied",
SPAM = "spam",
}
export interface EventImageData {
url: string
}
@ -35,6 +45,8 @@ export const EventDetailsDataFragment = gql`
start
end
}
publishedState
revisionState
images {
cover {
...EventImageData
@ -79,6 +91,8 @@ export interface EventDetailsData {
language
title
}>
revisionState: EventRevisionState
publishedState: EventPublishedState
images: EventImagesData
occurrences: {
id: string

View File

@ -11,11 +11,13 @@ import Login from "./Auth/Login"
import Signout from "./Auth/Signout"
import Signup from "./Auth/Signup"
import { useAppContext } from "./Context/AppContext"
import EventDetails from "./Event/EventDetails"
import EventDetailsRoute from "./Event/EventDetailsRoute"
import OccurrenceDetails from "./Event/OccurrenceDetails"
const Routes = () => {
const { me } = useAppContext()
const roles = me?.roles?.map(role => role.type)
const roles = me?.roles?.map(role => role.type)
return (
<Switch>
<Route path="/create" component={roles ? CreateEvent : Signup} />
@ -29,6 +31,10 @@ const Routes = () => {
path="/o/:sanitizedEventName/:occurrenceId"
component={OccurrenceDetails}
/>
<Route
path="/e/:sanitizedEventName/:eventId"
component={EventDetailsRoute}
/>
<Route path="/init-session/:hash" component={InitializeSession} />
<Route path="/login" component={Login} />
<Route path="/signup" component={Signup} />

View File

@ -16,8 +16,11 @@ const CreateEvent = (props: RouteComponentProps) => {
type: "success",
text: intl.get("event-create-success"),
})
props.history.push(`/o/aaa/${data.createEvent.occurrences[0].id}`)
if (data.createEvent.occurrences.length) {
props.history.push(`/o/aaa/${data.createEvent.occurrences[0].id}`)
} else {
props.history.push(`/e/aaa/${data.createEvent.id}`)
}
},
onError: error => {
addMessage({
@ -40,7 +43,7 @@ const CreateEvent = (props: RouteComponentProps) => {
...values.time,
timeZone: "Europe/Madrid",
},
status: "confirmed",
publishedState: values.publishedState,
tagNames: values.tagNames,
},
},

View File

@ -11,7 +11,7 @@ import {
import * as React from "react"
import styled from "@emotion/styled"
import { hot } from "react-hot-loader"
import { EventStatus } from "../../../@types"
import {EventPublishedState, EventStatus} from "../../../@types"
import * as intl from "react-intl-universal"
import TagSelector from "../EventTags/TagsSelector"
import messages from "./EventForm.msg.json"
@ -47,6 +47,7 @@ export interface EventFormData {
}
status: EventStatus
tagNames: string[]
publishedState: EventPublishedState
}
const todayMidday = new Date()
@ -106,6 +107,7 @@ const EventForm = (props: Props) => {
},
tagNames: [],
status: "confirmed",
publishedState: "published"
} as EventFormData)
}
validate={(values: EventFormData) => {

View File

@ -13,6 +13,8 @@ type CalendarEvent {
location: Location!
occurrences: [EventOccurrence]
owner: User!
publishedState: EventPublishedState!
revisionState: EventRevisionState!
status: EventStatus!
tags: [EventTag]
time: EventTime!
@ -29,6 +31,7 @@ type EventImage {
type EventImages {
cover: EventImage
event: CalendarEvent
gallery: [EventImage!]
poster: EventImage
thumb: EventImage
@ -47,6 +50,18 @@ type EventOccurrence {
start: String!
}
type EventRevision {
accepting: Boolean
author: User!
comment: String
createdAt: Date!
denying: Boolean
event: CalendarEvent!
id: ID!
spam: Boolean
submittedAt: Date
}
type EventTag {
id: ID!
name: String!
@ -79,13 +94,17 @@ type Mutation {
createEventTag(input: CreateEventTagInput!): EventTag
deleteEvent(id: ID!): User!
deleteEventTag(input: DeleteEventTagInput!): [EventTag]
dismissOpenEventRevision(input: EventRevisionInput!): EventRevision
grantRole(input: GrantRoleInput!): User!
removeEventGalleryImages(input: EventGalleryImagesInput!): CalendarEvent
requestEventRevision(input: RequestRevisionInput!): CalendarEvent
requestInvite(input: RequestInviteInput!): Boolean!
revokeRole(input: GrantRoleInput!): User!
setEventImage(input: EventImageUploadInput!): CalendarEvent
signin(input: SigninInput!): UserSession!
signup(input: SignupInput!): [Error]
startEventRevision(input: StartEventRevisionInput!): EventRevision
submitEventRevision(input: ReviseEventInput!): EventRevision
unsetEventImage(id: UnsetEventImageInput!): CalendarEvent
updateEvent(input: UpdateEventInput!): CalendarEvent
updateEventTag(input: UpdateEventTagInput!): EventTag
@ -130,7 +149,7 @@ enum CacheControlScope {
input CreateEventInput {
infos: [EventInformationInput]!
location: EventLocationInput!
status: String!
publishedState: EventPublishedState!
tagNames: [String!]!
time: EventTimeInput!
}
@ -176,6 +195,10 @@ input EventLocationInput {
name: String
}
input EventRevisionInput {
revisionId: ID!
}
input EventTimeInput {
end: Timestamp!
exceptions: String
@ -209,6 +232,18 @@ input RequestInviteInput {
email: String!
}
input RequestRevisionInput {
eventId: ID!
}
input ReviseEventInput {
accepting: Boolean!
comment: String
denying: Boolean!
revisionId: ID!
spam: Boolean!
}
input RevokeRoleInput {
roleType: RoleType!
userId: ID!
@ -224,6 +259,10 @@ input SignupInput {
username: String!
}
input StartEventRevisionInput {
eventId: ID!
}
input UnsetEventImageInput {
eventId: ID!
imageType: EventImageType
@ -233,6 +272,7 @@ input UpdateEventInput {
id: ID!
infos: [EventInformationInput!]
location: EventLocationInput
publishedState: EventPublishedState!
status: String
tagNames: [String!]!
time: EventTimeInput
@ -251,6 +291,10 @@ scalar Timestamp
scalar EventStatus
scalar EventPublishedState
scalar EventRevisionState
scalar RoleType
scalar Category