Skip to content

Commit

Permalink
DYNAMIC PRICING MANAGEMENT
Browse files Browse the repository at this point in the history
With this update, the ADMIN user can now change the characteristics of echan pricing plan from the UI. All the restrictions will then be applied automatically.
  • Loading branch information
Alex-GF authored May 30, 2023
2 parents 705b5a1 + 0a88c55 commit e318f8d
Show file tree
Hide file tree
Showing 61 changed files with 1,066 additions and 2,379 deletions.
6 changes: 4 additions & 2 deletions frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { ErrorBoundary } from "react-error-boundary";
import AppNavbar from "./AppNavbar";
import Home from "./home";
import PrivateRoute from "./privateRoute";
import PricingPlan from "./owner/plan";
import Register from "./auth/register";
import Login from "./auth/login";
import Logout from "./auth/logout";
Expand Down Expand Up @@ -47,6 +46,8 @@ import ConsultationListClinicOwner from "./clinicOwner/consultations/Consultatio
import ConsultationEditClinicOwner from "./clinicOwner/consultations/ConsultationEditClinicOwner";
import VetListClinicOwner from "./clinicOwner/vets/VetListClinicOwner";
import VetEditClinicOwner from "./clinicOwner/vets/VetEditClinicOwner";
import PlanListAdmin from "./admin/plans/PlanListAdmin";
import PlanEditAdmin from "./admin/plans/PlanEditAdmin";

function ErrorFallback({ error, resetErrorBoundary }) {
return (
Expand Down Expand Up @@ -98,13 +99,14 @@ function App() {
<Route path="/consultations" exact={true} element={<PrivateRoute><ConsultationListAdmin /></PrivateRoute>} />
<Route path="/consultations/:consultationId" exact={true} element={<PrivateRoute><ConsultationEditAdmin /></PrivateRoute>} />
<Route path="/consultations/:consultationId/tickets" exact={true} element={<PrivateRoute><TicketListAdmin /></PrivateRoute>} />
<Route path="/plansAdmin" exact={true} element={<PrivateRoute><PlanListAdmin /></PrivateRoute>} />
<Route path="/plansAdmin/:id" exact={true} element={<PrivateRoute><PlanEditAdmin /></PrivateRoute>} />
</>)
}
if (role === "OWNER") {
ownerRoutes = (
<>
<Route path="/dashboard" element={<PrivateRoute><OwnerDashboard /></PrivateRoute>} />
<Route path="/plan" exact={true} element={<PrivateRoute><PricingPlan /></PrivateRoute>} />
<Route path="/myPets" exact={true} element={<PrivateRoute><OwnerPetList /></PrivateRoute>} />
<Route path="/myPets/:id" exact={true} element={<PrivateRoute><OwnerPetEdit /></PrivateRoute>} />
<Route path="/myPets/:id/visits/:id" exact={true} element={<PrivateRoute><OwnerVisitEdit /></PrivateRoute>} />
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/AppNavbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ function AppNavbar() {
<NavItem>
<NavLink style={{ color: "white" }} tag={Link} to="/users">Users</NavLink>
</NavItem>
<NavItem>
<NavLink style={{ color: "white" }} tag={Link} to="/plansAdmin">Plans</NavLink>
</NavItem>
</>
)
}
Expand All @@ -62,9 +65,6 @@ function AppNavbar() {
<NavItem>
<NavLink style={{ color: "white" }} tag={Link} to="/consultations">Consultations</NavLink>
</NavItem>
<NavItem>
<NavLink style={{ color: "white" }} tag={Link} to="/plan">Plan</NavLink>
</NavItem>
</>
)
}
Expand Down
35 changes: 27 additions & 8 deletions frontend/src/admin/clinics/ClinicEditAdmin.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState } from "react";
import { Link } from "react-router-dom";
import { Button, Container, Form, FormGroup, Input, Label } from "reactstrap";
import { Form, Input, Label } from "reactstrap";
import tokenService from "../../services/token.service";
import getErrorModal from "../../util/getErrorModal";
import useFetchState from "../../util/useFetchState";
Expand All @@ -14,6 +14,10 @@ export default function ClinicEditAdmin() {
name: "",
address: "",
telephone: "",
plan: {
id: "",
name: "",
}
};
const id = getIdFromUrl(2);
const [message, setMessage] = useState(null);
Expand All @@ -35,19 +39,32 @@ export default function ClinicEditAdmin() {
setVisible
);

const [plans, setPlans] = useFetchState(
[],
`/api/v1/plans`,
jwt,
setMessage,
setVisible
);

function handleChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
setClinic({ ...clinic, [name]: value });
if (name === "plan"){
setClinic({ ...clinic, [name]: {
name: value
} });
}else{
setClinic({ ...clinic, [name]: value });
}
}

function handleSubmit(event) {
event.preventDefault();

clinic.clinicOwner = clinicOwners.filter((clinicOwner) => clinicOwner.id === parseInt(clinic.clinicOwner))[0];

console.log(clinic);
clinic.plan = plans.filter((plan) => plan.name === clinic.plan.name)[0];

fetch("/api/v1/clinics" + (clinic.id ? "/" + clinic.id : ""), {
method: clinic.id ? "PUT" : "POST",
Expand Down Expand Up @@ -127,14 +144,16 @@ export default function ClinicEditAdmin() {
name="plan"
required
type="select"
value={clinic.plan || ""}
value={clinic.plan.name || ""}
onChange={handleChange}
className="custom-input"
>
<option value="">None</option>
<option value="BASIC">BASIC</option>
<option value="GOLD">GOLD</option>
<option value="PLATINUM">PLATINUM</option>
{plans.map((plan) => {
return(
<option value={plan.name}>{plan.name}</option>
);
})}

</Input>
</div>
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/admin/clinics/ClinicListAdmin.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function ClinicListAdmin() {
<td>{clinic.address}</td>
<td>{clinic.telephone}</td>
<td>{clinic.clinicOwner.firstName} {clinic.clinicOwner.lastName}</td>
<td>{clinic.plan}</td>
<td>{clinic.plan.name}</td>
<td>
<ButtonGroup>
<Button
Expand Down Expand Up @@ -68,12 +68,12 @@ export default function ClinicListAdmin() {
return (
<div>
<div className="admin-page-container">
<h1 className="text-center">Clinic Owners</h1>
<h1 className="text-center">Clinics</h1>
{alerts.map((a) => a.alert)}
{modal}
<div className="float-right">
<Button color="success" tag={Link} to="/clinics/new">
Add Clinic Owner
Add Clinic
</Button>
</div>
<div>
Expand Down
213 changes: 213 additions & 0 deletions frontend/src/admin/plans/PlanEditAdmin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
import { useState } from "react";
import { Link } from "react-router-dom";
import { Form, Input, Label } from "reactstrap";
import tokenService from "../../services/token.service";
import getErrorModal from "../../util/getErrorModal";
import useFetchState from "../../util/useFetchState";
import getIdFromUrl from "../../util/getIdFromUrl";

const jwt = tokenService.getLocalAccessToken();

export default function PlanEditAdmin() {
const emptyItem = {
id: "",
name: "",
price: 0.0,
maxPets: 1,
maxVisitsPerMonthAndPet: 1,
supportPriority: "",
haveVetSelection: false,
haveCalendar: false,
havePetsDashboard: false,
haveOnlineConsultations: false,
};
const id = getIdFromUrl(2);
const [message, setMessage] = useState(null);
const [visible, setVisible] = useState(false);
const [plan, setPlan] = useFetchState(
emptyItem,
`/api/v1/plans/${id}`,
jwt,
setMessage,
setVisible,
id
);

function handleChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;

setPlan({ ...plan, [name]: value });
}

function handleCheckboxChange(event){
const target = event.target;
const name = target.name;

setPlan({ ...plan, [name]: target.checked ? true : false });
}

function handleSubmit(event) {
event.preventDefault();

fetch("/api/v1/plans" + (plan.id ? "/" + plan.id : ""), {
method: plan.id ? "PUT" : "POST",
headers: {
Authorization: `Bearer ${jwt}`,
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(plan),
})
.then((response) => response.json())
.then((json) => {
if (json.message) {
setMessage(json.message);
setVisible(true);
} else window.location.href = "/plansAdmin";
})
.catch((message) => alert(message));
}

const modal = getErrorModal(setVisible, visible, message);

return (
<div className="auth-page-container">
{<h2>{id !== "new" ? "Edit Plan" : "Add Plan"}</h2>}
{modal}
<div className="auth-form-container">
<Form onSubmit={handleSubmit}>
<div className="custom-form-input">
<Label for="name" className="custom-form-input-label">
Name
</Label>
<Input
type="text"
required
name="name"
id="name"
value={plan.name || ""}
onChange={handleChange}
className="custom-input"
/>
</div>
<div className="custom-form-input">
<Label for="name" className="custom-form-input-label">
Price (in €)
</Label>
<Input
type="number"
step="0.01"
required
name="price"
id="price"
value={plan.price || ""}
onChange={handleChange}
className="custom-input"
/>
</div>
<div className="custom-form-input">
<Label for="name" className="custom-form-input-label">
Max Pets
</Label>
<Input
type="number"
required
name="maxPets"
id="maxPets"
value={plan.maxPets || ""}
onChange={handleChange}
className="custom-input"
/>
</div>
<div className="custom-form-input">
<Label for="name" className="custom-form-input-label">
Max Visits per Pet and Month
</Label>
<Input
type="number"
required
name="maxVisitsPerMonthAndPet"
id="maxVisitsPerMonthAndPet"
value={plan.maxVisitsPerMonthAndPet || ""}
onChange={handleChange}
className="custom-input"
/>
</div>
<div className="custom-form-input">
<Label for="name" className="custom-form-input-label">
Max Visits per Pet and Month
</Label>
<Input
type="number"
required
name="maxVisitsPerMonthAndPet"
id="maxVisitsPerMonthAndPet"
value={plan.maxVisitsPerMonthAndPet || ""}
onChange={handleChange}
className="custom-input"
/>
</div>
<div className="custom-form-input">
<Label for="name" className="custom-form-input-label">
Support Priority
</Label>
<Input
id="supportPriority"
name="supportPriority"
required
type="select"
value={plan.supportPriority || ""}
onChange={handleChange}
className="custom-input"
>
<option value="">None</option>
<option value="LOW">LOW</option>
<option value="MEDIUM">MEDIUM</option>
<option value="HIGH">HIGH</option>
</Input>
</div>
<div className="checkbox-row">
Have vet selection
<label class="checkbox-container">
<Input type="checkbox" name="haveVetSelection" id="haveVetSelection" checked={plan.haveVetSelection} onChange={handleCheckboxChange}/>
<div class="checkbox-checkmark"></div>
</label>
</div>
<div className="checkbox-row">
Have calendar
<label class="checkbox-container">
<Input type="checkbox" name="haveCalendar" id="haveCalendar" checked={plan.haveCalendar} onChange={handleCheckboxChange}/>
<div class="checkbox-checkmark"></div>
</label>
</div>
<div className="checkbox-row">
Have pets dashboard
<label class="checkbox-container">
<Input type="checkbox" name="havePetsDashboard" id="havePetsDashboard" checked={plan.havePetsDashboard} onChange={handleCheckboxChange}/>
<div class="checkbox-checkmark"></div>
</label>
</div>
<div className="checkbox-row">
Have online consultations
<label class="checkbox-container">
<Input type="checkbox" name="haveOnlineConsultations" id="haveOnlineConsultations" checked={plan.haveOnlineConsultations} onChange={handleCheckboxChange}/>
<div class="checkbox-checkmark"></div>
</label>
</div>
<div className="custom-button-row">
<button className="auth-button">Save</button>
<Link
to={`/clinicOwners`}
className="auth-button"
style={{ textDecoration: "none" }}
>
Cancel
</Link>
</div>
</Form>
</div>
</div>
);
}
Loading

0 comments on commit e318f8d

Please sign in to comment.