Skip to content

Commit 8ca7470

Browse files
authored
Merge pull request #23 from OzPol/OzPol-7.18
Oz pol 7.18
2 parents 6b99efd + af9100a commit 8ca7470

File tree

89 files changed

+4715
-1430
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+4715
-1430
lines changed

Diff for: .env

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
DATABASE_URL=postgres://u7gijcrolofafo:p06abc391519c2278b6f469cd4409609f70c19e50566a11f974375dad824d93d8@c6sfjnr30ch74e.cluster-czrs8kj4isg7.us-east-1.rds.amazonaws.com:5432/dav0d71pkf8drf
2+
EMAIL_USERNAME=[email protected]
3+
EMAIL_PASSWORD=ServiceSynergyRocks<3!
4+
HEROKU_API_KEY=HRKU-4630122e-6673-4909-b54d-3ae9a8d9878d

Diff for: .vscode/settings.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"cSpell.words": [
3+
"hookform"
4+
]
5+
}

Diff for: app/favicon-original.ico

25.3 KB
Binary file not shown.

Diff for: app/favicon.ico

243 KB
Binary file not shown.

Diff for: app/free-repair-1892298-1606884.webp

19.5 KB
Binary file not shown.

Diff for: app/layout.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// app/layout.tsx
12
import type { Metadata } from "next";
23
import { Inter } from "next/font/google";
34
import "../styles/globals.css";
@@ -20,3 +21,5 @@ export default function RootLayout({
2021
</html>
2122
);
2223
}
24+
25+

Diff for: app/repairicon.png

176 KB
Loading

Diff for: components/AvailabilityCalendar.tsx

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// ./components/AvailabilityCalendar.tsx
2+
3+
import React, { useState } from 'react';
4+
import Calendar, { CalendarProps } from 'react-calendar';
5+
import 'react-calendar/dist/Calendar.css';
6+
7+
const AvailabilityCalendar = ({ availableDates }: { availableDates: Date[] }) => {
8+
const [selectedDate, setSelectedDate] = useState<Date | null>(null);
9+
10+
const isAvailable = (date: Date) => {
11+
return availableDates.some(availableDate => availableDate.toDateString() === date.toDateString());
12+
};
13+
14+
const handleDateChange: CalendarProps['onChange'] = (date, event) => {
15+
if (Array.isArray(date)) {
16+
setSelectedDate(date[0]);
17+
} else {
18+
setSelectedDate(date);
19+
}
20+
};
21+
22+
return (
23+
<div>
24+
<h2 className="text-2xl mb-4">Check Availability</h2>
25+
<Calendar
26+
onChange={handleDateChange}
27+
value={selectedDate}
28+
tileClassName={({ date }) => (isAvailable(date) ? 'bg-green-500 text-white' : '')}
29+
/>
30+
{selectedDate && (
31+
<p className="mt-4">
32+
Selected Date: {selectedDate.toDateString()}
33+
</p>
34+
)}
35+
</div>
36+
);
37+
};
38+
39+
export default AvailabilityCalendar;

Diff for: components/BookingForm.tsx

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// components/BookingForm.tsx
2+
3+
'use client';
4+
5+
import { zodResolver } from '@hookform/resolvers/zod';
6+
import { useForm } from 'react-hook-form';
7+
import { useRouter } from 'next/router';
8+
import { z } from 'zod';
9+
import { getBookingSchema } from '../lib/validation';
10+
import CustomFormField, { FormFieldType } from './CustomFormField';
11+
import SubmitButton from './SubmitButton';
12+
import { createBooking } from '../lib/booking.actions';
13+
14+
const BookingForm = () => {
15+
const router = useRouter();
16+
const form = useForm<z.infer<ReturnType<typeof getBookingSchema>>>({
17+
resolver: zodResolver(getBookingSchema('create')),
18+
defaultValues: {
19+
service: '',
20+
date: new Date(),
21+
time: '',
22+
},
23+
});
24+
25+
const onSubmit = async (values: z.infer<ReturnType<typeof getBookingSchema>>) => {
26+
try {
27+
await createBooking(values);
28+
router.push('/customerProfile'); // Redirect after booking
29+
} catch (error) {
30+
console.error('Error creating booking:', error);
31+
}
32+
};
33+
34+
return (
35+
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
36+
<CustomFormField
37+
fieldType={FormFieldType.INPUT}
38+
control={form.control}
39+
name="service"
40+
label="Service"
41+
placeholder="Service"
42+
/>
43+
<CustomFormField
44+
fieldType={FormFieldType.DATE_PICKER}
45+
control={form.control}
46+
name="date"
47+
label="Date"
48+
dateFormat="MM/dd/yyyy"
49+
/>
50+
<CustomFormField
51+
fieldType={FormFieldType.INPUT}
52+
control={form.control}
53+
name="time"
54+
label="Time"
55+
placeholder="Time"
56+
/>
57+
<SubmitButton isLoading={false}>Create Booking</SubmitButton>
58+
</form>
59+
);
60+
};
61+
62+
export default BookingForm;

Diff for: components/CreateUserPage.tsx

+202
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
// Moving from Shawn's register.tsx page to CreateUserPage.tsx component as intended
2+
'use client'
3+
import React, { useState } from 'react';
4+
import { useRouter } from 'next/router';
5+
import { users, databases } from '../lib/appwrite.config';
6+
7+
const CreateUserPage: React.FC = () => {
8+
const router = useRouter();
9+
const [userId, setUserId] = useState('');
10+
const [email, setEmail] = useState('');
11+
const [phone, setPhone] = useState('');
12+
const [name, setName] = useState('');
13+
const [address, setAddress] = useState('');
14+
const [city, setCity] = useState('');
15+
const [state, setState] = useState('');
16+
const [zipcode, setZipcode] = useState('');
17+
const [createon, setCreateon] = useState(new Date().toISOString());
18+
const [bookings, setBookings] = useState<string[]>([]);
19+
const [userType, setUserType] = useState<'Consumer'>('Consumer');
20+
const [profileImg, setProfileImg] = useState('');
21+
const [password, setPassword] = useState('');
22+
const [message, setMessage] = useState('');
23+
const [isUserCreated, setIsUserCreated] = useState(false);
24+
25+
const handleSubmit = async (e: React.FormEvent) => {
26+
e.preventDefault();
27+
28+
try {
29+
// Creating new user auth on Appwrite
30+
const newUser = await users.create('unique()', email, phone, password, name);
31+
// users.updatePhone(newUser.$id, phone);
32+
await users.updateLabels(newUser.$id, [userType]);
33+
34+
// Creating new consumer document in Appwrite
35+
const consumer = await databases.createDocument(
36+
process.env.DATABASE_ID!,//DBID
37+
process.env.CONSUMER_COLLECTION_ID!,//Collection ID
38+
'unique()',
39+
{
40+
userId: newUser.$id,
41+
email,
42+
phone,
43+
name,
44+
address,
45+
city,
46+
state,
47+
zipcode,
48+
createon,
49+
bookings,
50+
userType,
51+
profileImg,
52+
}
53+
);
54+
55+
setMessage(`User ${newUser.name} created successfully as a Consumer`);
56+
setIsUserCreated(true);
57+
} catch (error:any) {
58+
console.error('Error creating user or consumer:', error);
59+
console.log(error.code+":"+error.type);
60+
setMessage('Error creating user or consumer');
61+
}
62+
};
63+
64+
const handleGoBack = () => {
65+
router.push('/');
66+
};
67+
68+
return (
69+
<div className="flex items-center justify-center min-h-screen bg-gray-100" style={{ backgroundImage: "url('https://www.blurb.com/blog/wp-content/uploads/2023/06/How-to-Design-a-Book-Cover_1.jpg')" }}>
70+
<div className="bg-white p-6 rounded-lg shadow-md w-full max-w-md">
71+
<h1 className="text-2xl font-bold mb-4 text-center">Create User</h1>
72+
<form onSubmit={handleSubmit} className="space-y-3">
73+
<div className="flex flex-col">
74+
<label htmlFor="email" className="font-semibold">
75+
<span className="text-red-500">*</span> Email:
76+
</label>
77+
<input
78+
type="email"
79+
id="email"
80+
value={email}
81+
onChange={(e) => setEmail(e.target.value)}
82+
required
83+
className="border border-gray-300 rounded p-1 mt-1"
84+
/>
85+
</div>
86+
<div className="flex flex-col">
87+
<label htmlFor="password" className="font-semibold">
88+
<span className="text-red-500">*</span> Password:
89+
</label>
90+
<input
91+
type="password"
92+
id="password"
93+
value={password}
94+
onChange={(e) => setPassword(e.target.value)}
95+
required
96+
className="border border-gray-300 rounded p-1 mt-1"
97+
/>
98+
</div>
99+
<div className="flex flex-col">
100+
<label htmlFor="phone" className="font-semibold">
101+
<span className="text-red-500">*</span> Phone:
102+
</label>
103+
<input
104+
type="text"
105+
id="phone"
106+
value={phone}
107+
onChange={(e) => setPhone(e.target.value)}
108+
required
109+
className="border border-gray-300 rounded p-1 mt-1"
110+
/>
111+
</div>
112+
<div className="flex flex-col">
113+
<label htmlFor="name" className="font-semibold">
114+
<span className="text-red-500">*</span> Name:
115+
</label>
116+
<input
117+
type="text"
118+
id="name"
119+
value={name}
120+
onChange={(e) => setName(e.target.value)}
121+
required
122+
className="border border-gray-300 rounded p-1 mt-1"
123+
/>
124+
</div>
125+
<div className="flex flex-col">
126+
<label htmlFor="address" className="font-semibold">Address:</label>
127+
<input
128+
type="text"
129+
id="address"
130+
value={address}
131+
onChange={(e) => setAddress(e.target.value)}
132+
className="border border-gray-300 rounded p-1 mt-1"
133+
/>
134+
</div>
135+
<div className="flex flex-col">
136+
<label htmlFor="city" className="font-semibold">City:</label>
137+
<input
138+
type="text"
139+
id="city"
140+
value={city}
141+
onChange={(e) => setCity(e.target.value)}
142+
className="border border-gray-300 rounded p-1 mt-1"
143+
/>
144+
</div>
145+
<div className="flex flex-col">
146+
<label htmlFor="state" className="font-semibold">State:</label>
147+
<input
148+
type="text"
149+
id="state"
150+
value={state}
151+
onChange={(e) => setState(e.target.value)}
152+
className="border border-gray-300 rounded p-1 mt-1"
153+
/>
154+
</div>
155+
<div className="flex flex-col">
156+
<label htmlFor="zipcode" className="font-semibold">Zipcode:</label>
157+
<input
158+
type="text"
159+
id="zipcode"
160+
value={zipcode}
161+
onChange={(e) => setZipcode(e.target.value)}
162+
className="border border-gray-300 rounded p-1 mt-1"
163+
/>
164+
</div>
165+
<div className="flex flex-col">
166+
<label htmlFor="profileImg" className="font-semibold">Profile Image URL:</label>
167+
<input
168+
type="url"
169+
id="profileImg"
170+
value={profileImg}
171+
onChange={(e) => setProfileImg(e.target.value)}
172+
className="border border-gray-300 rounded p-1 mt-1"
173+
/>
174+
</div>
175+
<div className="flex flex-col">
176+
<label htmlFor="userType" className="font-semibold">User Type:</label>
177+
<select
178+
id="userType"
179+
value={userType}
180+
onChange={(e) => setUserType(e.target.value as 'Consumer')}
181+
required
182+
className="border border-gray-300 rounded p-1 mt-1"
183+
>
184+
<option value="Consumer">Consumer</option>
185+
{/* <option value="Provider">Provider</option>
186+
<option value="Admin">Admin</option> */}
187+
</select>
188+
</div>
189+
<div className="flex justify-center">
190+
{!isUserCreated && <button className="bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-600" type="submit">Create User</button>}
191+
</div>
192+
</form>
193+
{message && <p className="mt-4 text-center text-green-500">{message}</p>}
194+
<div className="flex justify-center mt-1">
195+
<button className="bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-600" onClick={handleGoBack}>Back to Login</button>
196+
</div>
197+
</div>
198+
</div>
199+
);
200+
};
201+
202+
export default CreateUserPage;

0 commit comments

Comments
 (0)