Table updates for new appointments fields. Schedule modal baseline functionality. Refactor schedule components to be more reusable.

This commit is contained in:
Patrick Fic
2020-02-06 13:39:39 -08:00
parent 1a14fb8da6
commit fae1e8cdeb
35 changed files with 785 additions and 67 deletions

View File

@@ -18,6 +18,178 @@
<folder_node> <folder_node>
<name>translation</name> <name>translation</name>
<children> <children>
<folder_node>
<name>appointments</name>
<children>
<folder_node>
<name>actions</name>
<children>
<concept_node>
<name>cancel</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>intake</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>reschedule</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>viewjob</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
<name>errors</name>
<children>
<concept_node>
<name>saving</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
<name>labels</name>
<children>
<concept_node>
<name>nodateselected</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
<name>successes</name>
<children>
<concept_node>
<name>created</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
</children>
</folder_node>
<folder_node> <folder_node>
<name>associations</name> <name>associations</name>
<children> <children>
@@ -3012,6 +3184,27 @@
<folder_node> <folder_node>
<name>labels</name> <name>labels</name>
<children> <children>
<concept_node>
<name>appointmentconfirmation</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>available_new_jobs</name> <name>available_new_jobs</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>

View File

@@ -14,8 +14,6 @@ import SpinnerComponent from "../components/loading-spinner/loading-spinner.comp
import errorLink from "../graphql/apollo-error-handling"; import errorLink from "../graphql/apollo-error-handling";
import App from "./App"; import App from "./App";
class AppContainer extends Component { class AppContainer extends Component {
state = { state = {
client: null, client: null,

View File

@@ -22,7 +22,7 @@ export default function JobsDetailHeader({
scheduleModalState scheduleModalState
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [scheduleModalVisible, setscheduleModalVisible] = scheduleModalState; const setscheduleModalVisible = scheduleModalState[1];
const tombstoneTitle = ( const tombstoneTitle = (
<div> <div>

View File

@@ -4,5 +4,5 @@ import "./loading-skeleton.styles.scss";
import { Skeleton } from "antd"; import { Skeleton } from "antd";
export default function LoadingSkeleton(props) { export default function LoadingSkeleton(props) {
return <Skeleton {...props} className='loading-skeleton' active />; return <Skeleton {...props} className="loading-skeleton" active />;
} }

View File

@@ -0,0 +1,33 @@
import moment from "moment";
import React from "react";
import { Calendar, momentLocalizer } from "react-big-calendar";
import "react-big-calendar/lib/css/react-big-calendar.css";
import DateCellWrapper from "../schedule-datecellwrapper/schedule-datecellwrapper.component";
import Event from "../schedule-event/schedule-event.container";
const localizer = momentLocalizer(moment);
export default function ScheduleCalendarWrapperComponent({
data,
refetch,
defaultView,
...otherProps
}) {
return (
<Calendar
events={data}
defaultView={defaultView}
step={30}
showMultiDayTimes
localizer={localizer}
min={new Date("2020-01-01T06:00:00")} //TODO: Read from business settings.
max={new Date("2020-01-01T20:00:00")}
components={{
event: e => {
return Event({ event: e.event, refetch: refetch });
},
dateCellWrapper: DateCellWrapper
}}
{...otherProps}
/>
);
}

View File

@@ -1,27 +1,13 @@
import moment from "moment";
import React from "react"; import React from "react";
import { Calendar, momentLocalizer } from "react-big-calendar";
import "react-big-calendar/lib/css/react-big-calendar.css"; import "react-big-calendar/lib/css/react-big-calendar.css";
import DateCellWrapper from "../schedule-datecellwrapper/schedule-datecellwrapper.component"; import ScheduleCalendarWrapperComponent from "../schedule-calendar-wrapper/scheduler-calendar-wrapper.component";
import Event from "../schedule-event/schedule-event.component";
const localizer = momentLocalizer(moment);
export default function ScheduleCalendarComponent({ data }) { export default function ScheduleCalendarComponent({ data, refetch }) {
return ( return (
<Calendar <ScheduleCalendarWrapperComponent
events={data} data={data}
defaultView="week" defaultView="week"
//views={allViews} refetch={refetch}
step={30}
showMultiDayTimes
localizer={localizer}
min={new Date("2020-01-01T06:00:00")} //TODO: Read from business settings.
max={new Date("2020-01-01T20:00:00")}
//onSelectEvent={event => console.log("event", event)}
components={{
event: Event,
dateCellWrapper: DateCellWrapper
}}
/> />
); );
} }

View File

@@ -1,14 +1,17 @@
import React from "react"; import React from "react";
import { useQuery } from "react-apollo"; import { useQuery } from "react-apollo";
import ScheduleCalendarComponent from "./schedule-calendar.component"; import ScheduleCalendarComponent from "./schedule-calendar.component";
import { QUERY_ALL_APPOINTMENTS } from "../../graphql/appointments.queries"; import { QUERY_ALL_ACTIVE_APPOINTMENTS } from "../../graphql/appointments.queries";
import LoadingSpinner from "../loading-spinner/loading-spinner.component"; import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
export default function ScheduleCalendarContainer() { export default function ScheduleCalendarContainer() {
const { loading, error, data, refetch } = useQuery(QUERY_ALL_APPOINTMENTS, { const { loading, error, data, refetch } = useQuery(
fetchPolicy: "network-only" QUERY_ALL_ACTIVE_APPOINTMENTS,
}); {
fetchPolicy: "network-only"
}
);
if (loading) return <LoadingSpinner />; if (loading) return <LoadingSpinner />;
if (error) return <AlertComponent message={error.message} type="error" />; if (error) return <AlertComponent message={error.message} type="error" />;

View File

@@ -2,22 +2,16 @@ import React from "react";
export default function ScheduleDateCellWrapper(dateCellWrapperProps) { export default function ScheduleDateCellWrapper(dateCellWrapperProps) {
// Show 'click me' text in arbitrary places by using the range prop // Show 'click me' text in arbitrary places by using the range prop
const hasAlert = dateCellWrapperProps.range
? dateCellWrapperProps.range.some(date => {
return date.getDate() % 12 === 0;
})
: false;
const style = { const style = {
display: "flex", display: "flex",
flex: 1, flex: 1,
borderLeft: "1px solid #DDD", borderLeft: "1px solid #DDD",
backgroundColor: hasAlert ? "#f5f5dc" : "#fff" backgroundColor: "#fff"
}; };
return ( return (
<div style={style}> <div style={style}>
DateCellWrapper PLACEHOLDER:DATA
{hasAlert && <button onClick={e => alert(e)}>Click me</button>}
{dateCellWrapperProps.children} {dateCellWrapperProps.children}
</div> </div>
); );

View File

@@ -0,0 +1,20 @@
import React from "react";
import "react-big-calendar/lib/css/react-big-calendar.css";
import { useTranslation } from "react-i18next";
import ScheduleCalendarWrapperComponent from "../schedule-calendar-wrapper/scheduler-calendar-wrapper.component";
export default function ScheduleDayViewComponent({ data, day }) {
const { t } = useTranslation();
if (data)
//TODO Remove addtional calendar elements from day view.
return (
<ScheduleCalendarWrapperComponent
events={data}
defaultView="day"
style={{ height: "40vh" }}
defaultDate={new Date(day)}
//onNavigate={e => console.log("e", e)}
/>
);
else return <div>{t("appointments.labels.nodateselected")}</div>;
}

View File

@@ -0,0 +1,36 @@
import React from "react";
import ScheduleDayViewComponent from "./schedule-day-view.component";
import { useQuery } from "react-apollo";
import { QUERY_APPOINTMENT_BY_DATE } from "../../graphql/appointments.queries";
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
import moment from "moment";
export default function ScheduleDayViewContainer({ day }) {
const { loading, error, data } = useQuery(QUERY_APPOINTMENT_BY_DATE, {
variables: {
start: moment(day).startOf("day"),
end: moment(day).endOf("day")
},
skip: !day,
fetchPolicy: "network-only"
});
if (loading) return <LoadingSkeleton paragraph={{ rows: 4 }} />;
if (error) return <div>{error.message}</div>;
let normalizedData;
if (data) {
normalizedData = data.appointments.map(e => {
//Required becuase Hasura returns a string instead of a date object.
return Object.assign(
{},
e,
{ start: new Date(e.start) },
{ end: new Date(e.end) }
);
});
}
return (
<ScheduleDayViewComponent data={data ? normalizedData : null} day={day} />
);
}

View File

@@ -5,7 +5,7 @@ import PhoneFormatter from "../../utils/PhoneFormatter";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
export default function Event({ event }) { export default function ScheduleEventComponent({ event, handleCancel }) {
const { t } = useTranslation(); const { t } = useTranslation();
const popoverContent = ( const popoverContent = (
<div> <div>
@@ -23,19 +23,35 @@ export default function Event({ event }) {
<PhoneFormatter>{event.job.ownr_ph1}</PhoneFormatter> <PhoneFormatter>{event.job.ownr_ph1}</PhoneFormatter>
</div> </div>
<Link to={`/manage/jobs/${event.job.id}`}> <Link to={`/manage/jobs/${event.job.id}`}>
<Button>View Job</Button> <Button>{t("appointments.actions.viewjob")}</Button>
</Link> </Link>
<Button>//TODO: Reschedule</Button> <Button onClick={() => handleCancel(event.id)}>
<Button>//TODO: Intake</Button> {t("appointments.actions.cancel")}
</Button>
<Button>
{
//TODO: Add reschedule Func.
}
{t("appointments.actions.reschedule")}
</Button>
<Button>
{
//TODO: Add intake func.
}
{t("appointments.actions.intake")}
</Button>
</div> </div>
); );
return ( return (
<Popover content={popoverContent}> <Popover content={popoverContent}>
<strong>{`${event.job.ownr_fn || ""} ${event.job.ownr_ln || ""}`}</strong>
<div> <div>
{`${event.job.vehicle.v_model_yr || ""} ${event.job.vehicle <strong>{`${event.job.ownr_fn || ""} ${event.job.ownr_ln ||
.v_make_desc || ""} ${event.job.vehicle.v_model_desc || ""}`} ""}`}</strong>
<span style={{ margin: 4 }}>
{`${event.job.vehicle.v_model_yr || ""} ${event.job.vehicle
.v_make_desc || ""} ${event.job.vehicle.v_model_desc || ""}`}
</span>
</div> </div>
</Popover> </Popover>
); );

View File

@@ -0,0 +1,16 @@
import React from "react";
import { useMutation } from "react-apollo";
import { CANCEL_APPOINTMENT_BY_ID } from "../../graphql/appointments.queries";
import ScheduleEventComponent from "./schedule-event.component";
export default function ScheduleEventContainer({ event, refetch }) {
const [cancelAppointment] = useMutation(CANCEL_APPOINTMENT_BY_ID);
console.log("refetch", refetch);
const handleCancel = id => {
cancelAppointment({ variables: { appid: event.id } }).then(r => {
if (refetch) refetch();
});
};
return <ScheduleEventComponent event={event} handleCancel={handleCancel} />;
}

View File

@@ -1,35 +1,57 @@
import { Checkbox, DatePicker, Modal, Tabs, TimePicker, Col, Row } from "antd";
import React from "react"; import React from "react";
import { Modal, Tabs, DatePicker, TimePicker } from "antd"; import { useTranslation } from "react-i18next";
import moment from "moment"; import ScheduleDayViewContainer from "../schedule-day-view/schedule-day-view.container";
export default function ScheduleJobModalComponent({ export default function ScheduleJobModalComponent({
appData, appData,
setAppData, setAppData,
formData,
setFormData,
...props ...props
}) { }) {
const { t } = useTranslation();
return ( return (
<Modal {...props} maskClosable={false}> <Modal {...props} width={"80%"} maskClosable={false}>
<Tabs defaultActiveKey="1"> <Tabs defaultActiveKey="1">
<Tabs.TabPane tab="SMART Scheduling" key="auto"> <Tabs.TabPane tab="SMART Scheduling" key="auto">
Automatic Job Selection. Automatic Job Selection.
</Tabs.TabPane> </Tabs.TabPane>
<Tabs.TabPane tab="Manual Scheduling" key="manual"> <Tabs.TabPane tab="Manual Scheduling" key="manual">
Manual Job Selection Scheduled Time <Row>
<DatePicker <Col span={14}>
value={appData.start} Manual Job Selection Scheduled Time
onChange={e => { <DatePicker
setAppData({ ...appData, start: e }); value={appData.start}
}} onChange={e => {
/> setAppData({ ...appData, start: e });
<TimePicker }}
value={appData.start} />
format={"HH:mm"} <TimePicker
minuteStep={15} value={appData.start}
onChange={e => { format={"HH:mm"}
setAppData({ ...appData, start: e }); minuteStep={15}
}} onChange={e => {
/> setAppData({ ...appData, start: e });
}}
/>
</Col>
<Col span={10}>
<ScheduleDayViewContainer day={appData.start} />
</Col>
</Row>
</Tabs.TabPane> </Tabs.TabPane>
</Tabs> </Tabs>
{
//TODO: Build out notifications.
}
<Checkbox
defaultChecked={formData.notifyCustomer}
onChange={e =>
setFormData({ ...formData, notifyCustomer: e.target.checked })
}
>
{t("jobs.labels.appointmentconfirmation")}
</Checkbox>
</Modal> </Modal>
); );
} }

View File

@@ -3,7 +3,8 @@ import ScheduleJobModalComponent from "./schedule-job-modal.component";
import { useMutation } from "react-apollo"; import { useMutation } from "react-apollo";
import { INSERT_APPOINTMENT } from "../../graphql/appointments.queries"; import { INSERT_APPOINTMENT } from "../../graphql/appointments.queries";
import moment from "moment"; import moment from "moment";
import { notification } from "antd";
import { useTranslation } from "react-i18next";
export default function ScheduleJobModalContainer({ export default function ScheduleJobModalContainer({
scheduleModalState, scheduleModalState,
jobId jobId
@@ -11,11 +12,15 @@ export default function ScheduleJobModalContainer({
const [scheduleModalVisible, setscheduleModalVisible] = scheduleModalState; const [scheduleModalVisible, setscheduleModalVisible] = scheduleModalState;
const [appData, setAppData] = useState({ jobid: jobId, start: null }); const [appData, setAppData] = useState({ jobid: jobId, start: null });
const [insertAppointment] = useMutation(INSERT_APPOINTMENT); const [insertAppointment] = useMutation(INSERT_APPOINTMENT);
const [formData, setFormData] = useState({ notifyCustomer: false });
const { t } = useTranslation();
return ( return (
<ScheduleJobModalComponent <ScheduleJobModalComponent
appData={appData} appData={appData}
setAppData={setAppData} setAppData={setAppData}
formData={formData}
setFormData={setFormData}
//Spreadable Modal Props //Spreadable Modal Props
visible={scheduleModalVisible} visible={scheduleModalVisible}
onCancel={() => setscheduleModalVisible(false)} onCancel={() => setscheduleModalVisible(false)}
@@ -25,9 +30,25 @@ export default function ScheduleJobModalContainer({
variables: { variables: {
app: { ...appData, end: moment(appData.start).add(60, "minutes") } app: { ...appData, end: moment(appData.start).add(60, "minutes") }
} }
}).then(r => { })
setscheduleModalVisible(false); .then(r => {
}); notification["success"]({
message: t("appointments.successes.created")
});
if (formData.notifyCustomer) {
//TODO: Implement customer reminder on scheduling.
alert("Chosed to notify the customer somehow!");
}
setscheduleModalVisible(false);
})
.catch(error => {
notification["error"]({
message: t("appointments.errors.saving", {
message: error.message
})
});
});
}} }}
/> />
); );

View File

@@ -1,8 +1,8 @@
import { gql } from "apollo-boost"; import { gql } from "apollo-boost";
export const QUERY_ALL_APPOINTMENTS = gql` export const QUERY_ALL_ACTIVE_APPOINTMENTS = gql`
query QUERY_ALL_APPOINTMENTS { query QUERY_ALL_ACTIVE_APPOINTMENTS {
appointments { appointments(where: { canceled: { _eq: false } }) {
start start
id id
end end
@@ -35,3 +35,42 @@ export const INSERT_APPOINTMENT = gql`
} }
} }
`; `;
export const QUERY_APPOINTMENT_BY_DATE = gql`
query QUERY_APPOINTMENT_BY_DATE($start: timestamptz, $end: timestamptz) {
appointments(where: { start: { _lte: $end, _gte: $start } }) {
start
id
end
job {
ro_number
ownr_ln
ownr_fn
ownr_ph1
ownr_ea
clm_total
id
clm_no
vehicle {
id
v_model_yr
v_make_desc
v_model_desc
}
}
}
}
`;
export const CANCEL_APPOINTMENT_BY_ID = gql`
mutation CANCEL_APPOINTMENT_BY_ID($appid: uuid!) {
update_appointments(
where: { id: { _eq: $appid } }
_set: { canceled: true }
) {
returning {
id
}
}
}
`;

View File

@@ -26,6 +26,9 @@ import UserActionTypes from "./user.types";
export function* signInWithEmail({ payload: { email, password } }) { export function* signInWithEmail({ payload: { email, password } }) {
try { try {
const { user } = yield auth.signInWithEmailAndPassword(email, password); const { user } = yield auth.signInWithEmailAndPassword(email, password);
let token = yield user.getIdToken();
localStorage.setItem("token", token);
window.sessionStorage.setItem(`lastTokenRefreshTime`, new Date());
yield put( yield put(
signInSuccess({ signInSuccess({
uid: user.uid, uid: user.uid,

View File

@@ -1,5 +1,22 @@
{ {
"translation": { "translation": {
"appointments": {
"actions": {
"cancel": "Cancel",
"intake": "Intake",
"reschedule": "Reschedule",
"viewjob": "View Job"
},
"errors": {
"saving": "Error scheduling appointment. {{message}}"
},
"labels": {
"nodateselected": "No date has been selected."
},
"successes": {
"created": "Appointment scheduled successfully."
}
},
"associations": { "associations": {
"actions": { "actions": {
"activate": "Activate" "activate": "Activate"
@@ -176,6 +193,7 @@
"vehicle": "Vehicle" "vehicle": "Vehicle"
}, },
"labels": { "labels": {
"appointmentconfirmation": "Send confirmation to customer?",
"available_new_jobs": "", "available_new_jobs": "",
"cards": { "cards": {
"appraiser": "Appraiser", "appraiser": "Appraiser",

View File

@@ -1,5 +1,22 @@
{ {
"translation": { "translation": {
"appointments": {
"actions": {
"cancel": "Cancelar",
"intake": "Consumo",
"reschedule": "Reprogramar",
"viewjob": "Ver trabajo"
},
"errors": {
"saving": "Error al programar la cita. {{message}}"
},
"labels": {
"nodateselected": "No se ha seleccionado ninguna fecha."
},
"successes": {
"created": "Cita programada con éxito."
}
},
"associations": { "associations": {
"actions": { "actions": {
"activate": "Activar" "activate": "Activar"
@@ -176,6 +193,7 @@
"vehicle": "Vehículo" "vehicle": "Vehículo"
}, },
"labels": { "labels": {
"appointmentconfirmation": "¿Enviar confirmación al cliente?",
"available_new_jobs": "", "available_new_jobs": "",
"cards": { "cards": {
"appraiser": "Tasador", "appraiser": "Tasador",

View File

@@ -1,5 +1,22 @@
{ {
"translation": { "translation": {
"appointments": {
"actions": {
"cancel": "annuler",
"intake": "Admission",
"reschedule": "Replanifier",
"viewjob": "Voir le travail"
},
"errors": {
"saving": "Erreur lors de la planification du rendez-vous. {{message}}"
},
"labels": {
"nodateselected": "Aucune date n'a été sélectionnée."
},
"successes": {
"created": "Rendez-vous planifié avec succès."
}
},
"associations": { "associations": {
"actions": { "actions": {
"activate": "Activer" "activate": "Activer"
@@ -176,6 +193,7 @@
"vehicle": "Véhicule" "vehicle": "Véhicule"
}, },
"labels": { "labels": {
"appointmentconfirmation": "Envoyer une confirmation au client?",
"available_new_jobs": "", "available_new_jobs": "",
"cards": { "cards": {
"appraiser": "Expert", "appraiser": "Expert",

View File

@@ -0,0 +1,17 @@
- args:
permission:
columns:
- authid
- email
- created_at
- updated_at
filter: {}
localPresets:
- key: ""
value: ""
set: {}
role: anonymous
table:
name: users
schema: public
type: create_update_permission

View File

@@ -0,0 +1,6 @@
- args:
role: anonymous
table:
name: users
schema: public
type: drop_update_permission

View File

@@ -0,0 +1,17 @@
- args:
permission:
check: {}
columns:
- authid
- created_at
- email
- updated_at
localPresets:
- key: ""
value: ""
set: {}
role: anonymous
table:
name: users
schema: public
type: create_insert_permission

View File

@@ -0,0 +1,6 @@
- args:
role: anonymous
table:
name: users
schema: public
type: drop_insert_permission

View File

@@ -0,0 +1,12 @@
- args:
permission:
allow_aggregations: false
columns:
- authid
computed_fields: []
filter: {}
role: anonymous
table:
name: users
schema: public
type: create_select_permission

View File

@@ -0,0 +1,6 @@
- args:
role: anonymous
table:
name: users
schema: public
type: drop_select_permission

View File

@@ -0,0 +1,3 @@
- args:
sql: ALTER TABLE "public"."appointments" DROP COLUMN "canceled";
type: run_sql

View File

@@ -0,0 +1,4 @@
- args:
sql: ALTER TABLE "public"."appointments" ADD COLUMN "canceled" boolean NOT NULL
DEFAULT false;
type: run_sql

View File

@@ -0,0 +1,3 @@
- args:
sql: ALTER TABLE "public"."appointments" DROP COLUMN "arrived";
type: run_sql

View File

@@ -0,0 +1,4 @@
- args:
sql: ALTER TABLE "public"."appointments" ADD COLUMN "arrived" boolean NOT NULL
DEFAULT false;
type: run_sql

View File

@@ -0,0 +1,34 @@
- args:
role: user
table:
name: appointments
schema: public
type: drop_insert_permission
- args:
permission:
check:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- created_at
- end
- start
- updated_at
- id
- jobid
localPresets:
- key: ""
value: ""
set: {}
role: user
table:
name: appointments
schema: public
type: create_insert_permission

View File

@@ -0,0 +1,36 @@
- args:
role: user
table:
name: appointments
schema: public
type: drop_insert_permission
- args:
permission:
check:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- arrived
- canceled
- created_at
- end
- start
- updated_at
- id
- jobid
localPresets:
- key: ""
value: ""
set: {}
role: user
table:
name: appointments
schema: public
type: create_insert_permission

View File

@@ -0,0 +1,32 @@
- args:
role: user
table:
name: appointments
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: false
columns:
- created_at
- end
- start
- updated_at
- id
- jobid
computed_fields: []
filter:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
role: user
table:
name: appointments
schema: public
type: create_select_permission

View File

@@ -0,0 +1,34 @@
- args:
role: user
table:
name: appointments
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: false
columns:
- arrived
- canceled
- created_at
- end
- start
- updated_at
- id
- jobid
computed_fields: []
filter:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
role: user
table:
name: appointments
schema: public
type: create_select_permission

View File

@@ -0,0 +1,34 @@
- args:
role: user
table:
name: appointments
schema: public
type: drop_update_permission
- args:
permission:
columns:
- created_at
- end
- start
- updated_at
- id
- jobid
filter:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
localPresets:
- key: ""
value: ""
set: {}
role: user
table:
name: appointments
schema: public
type: create_update_permission

View File

@@ -0,0 +1,36 @@
- args:
role: user
table:
name: appointments
schema: public
type: drop_update_permission
- args:
permission:
columns:
- arrived
- canceled
- created_at
- end
- start
- updated_at
- id
- jobid
filter:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
localPresets:
- key: ""
value: ""
set: {}
role: user
table:
name: appointments
schema: public
type: create_update_permission