Skip to content
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
16837b5
Create shared pnpm workspace package with driver type
benkoppe Dec 9, 2025
0009bd2
Add shared package as dependency to frontend and server
benkoppe Dec 9, 2025
c835f36
Replace all usage of driver class with definition in shared package
benkoppe Dec 9, 2025
0884fac
Remove exports specification from shared package.json
benkoppe Dec 9, 2025
8e2a489
Replace location type import with shared
benkoppe Dec 9, 2025
341e678
Replace admin type definition/imports with shared package
benkoppe Dec 9, 2025
febf716
Replace rider type definition/imports with shared package
benkoppe Dec 9, 2025
a3ae48a
Replace ride type definitions/imports with shared package
benkoppe Dec 9, 2025
91cabc1
Replace vehicle type definitions/imports with shared package
benkoppe Dec 9, 2025
c4c9b94
Replace server-side src/utils/types.ts with shared src/types/index.ts
benkoppe Dec 9, 2025
6fcffcc
Apply frontend-only filter to pnpm install for build-frontend stage
benkoppe Dec 9, 2025
8cf572f
Replace create-react-app with vite in frontend pacakge.json
benkoppe Dec 9, 2025
16d43b7
Add necessary vite-env.d.ts and vite.config.ts
benkoppe Dec 9, 2025
55bd0c6
Migrate index.html to vite standards
benkoppe Dec 9, 2025
8581f95
Convert all env vars to vite format
benkoppe Dec 9, 2025
fc79108
Convert all frontend env vars to vite format in CI
benkoppe Dec 9, 2025
ed3385d
Update all @carriage-web/shared imports to remove /src
benkoppe Dec 10, 2025
87e9806
Update moduleResolution and add references to both server/frontend ts…
benkoppe Dec 10, 2025
0fafcb7
Gitignore shared build outputs
benkoppe Dec 10, 2025
2a42b0d
Add build step to shared package.json and update tsconfig
benkoppe Dec 10, 2025
00357b3
Filter including dependencies in CI so shared package is included
benkoppe Dec 10, 2025
a4d0bff
Reformat with prettier
benkoppe Dec 10, 2025
cc859fa
Add dist/ to .prettierignore
benkoppe Dec 10, 2025
4260b07
Add dist/ to .eslintignore
benkoppe Dec 10, 2025
a5882e7
Remove src/ from @carriage-web imports in server tests
benkoppe Dec 10, 2025
56326e6
Fix some server imports to satisfy eslint
benkoppe Dec 10, 2025
1245074
Configure top-level eslint with eslint-import-resolver-typescript
benkoppe Dec 10, 2025
4044320
Remove nested lint scripts, now relying on top-level only
benkoppe Dec 10, 2025
9662e1b
Add build step for shared package to ci-check
benkoppe Dec 10, 2025
7e0a0a0
Merge branch 'bek76/pnpm-shared' into bek76/pnpm-vite
benkoppe Dec 10, 2025
dcbfcc5
Use `build` instead of `dist` for emitted `shared` build output
benkoppe Dec 10, 2025
883fa42
Add `dev` script to shared package.json
benkoppe Dec 10, 2025
60ebc3c
Merge branch 'bek76/pnpm-shared' into bek76/pnpm-vite
benkoppe Dec 10, 2025
c366022
Copy necessary built shared folder contents to final image
benkoppe Dec 10, 2025
2a8a264
Merge Dockerfile shared package fixes into bek76/pnpm-vite
benkoppe Dec 10, 2025
9756b8f
Merge branch 'bek76/pnpm-docker' into bek76/pnpm-shared
benkoppe Dec 10, 2025
bd9fbc0
Merge branch 'bek76/pnpm-shared' into bek76/pnpm-vite
benkoppe Dec 10, 2025
76a0a4e
Merge branch 'master' into bek76/pnpm-shared
mjaydenkim Mar 4, 2026
3bdb3f7
final fixes
mjaydenkim Mar 5, 2026
9c381b0
Merge branch 'bek76/pnpm-shared' into bek76/pnpm-vite
mjaydenkim Mar 5, 2026
87179c4
ITS ALIVEEEEE
mjaydenkim Mar 5, 2026
cf835e6
Merge pull request #635 from cornell-dti/bek76/pnpm-vite
mjaydenkim Mar 5, 2026
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
3 changes: 2 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
build
tests
tests
dist
15 changes: 15 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,20 @@ module.exports = {
react: {
version: 'detect',
},
'import/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx'],
},
'import/resolver': {
typescript: {
alwaysTryTypes: true,
project: [
'./tsconfig.base.json',
'./server/tsconfig.json',
'./frontend/tsconfig.json',
'./shared/tsconfig.json',
],
},
node: true,
},
},
};
4 changes: 2 additions & 2 deletions .github/workflows/ci-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ jobs:
- name: Install Dependencies
run: pnpm install --frozen-lockfile
- name: Build Frontend
run: CI='' pnpm run --filter frontend build
run: CI='' pnpm run --filter frontend... build
- name: Build Server
run: CI='' pnpm run --filter server build
run: CI='' pnpm run --filter server... build
2 changes: 2 additions & 0 deletions .github/workflows/ci-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ jobs:
pnpm install --frozen-lockfile
echo "Prettier version:"
pnpm prettier --version
- name: Build Shared Package
run: pnpm --filter shared... build
- name: Debug Prettier
run: |
echo "Files to be checked:"
Expand Down
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
build/
public/**.html
public/**.json
dist/
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@

FROM build-base AS build-frontend
COPY . .
# TODO: filter only frontend dependencies. until we add a shared package, we need all dependencies
RUN pnpm install -r --offline
RUN pnpm install -r --offline --filter frontend...

# Read build-time environment variables
ARG REACT_APP_SERVER_URL
Expand All @@ -39,10 +38,10 @@
ENV REACT_APP_CLIENT_ID=${REACT_APP_CLIENT_ID}
ARG REACT_APP_PUBLIC_VAPID_KEY
ENV REACT_APP_PUBLIC_VAPID_KEY=${REACT_APP_PUBLIC_VAPID_KEY}
ARG REACT_APP_ENCRYPTION_KEY

Check warning on line 41 in Dockerfile

View workflow job for this annotation

GitHub Actions / build-push

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "REACT_APP_ENCRYPTION_KEY") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENV REACT_APP_ENCRYPTION_KEY=${REACT_APP_ENCRYPTION_KEY}

Check warning on line 42 in Dockerfile

View workflow job for this annotation

GitHub Actions / build-push

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "REACT_APP_ENCRYPTION_KEY") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ARG REACT_APP_GOOGLE_MAPS_API_KEY

Check warning on line 43 in Dockerfile

View workflow job for this annotation

GitHub Actions / build-push

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "REACT_APP_GOOGLE_MAPS_API_KEY") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENV REACT_APP_GOOGLE_MAPS_API_KEY=${REACT_APP_GOOGLE_MAPS_API_KEY}

Check warning on line 44 in Dockerfile

View workflow job for this annotation

GitHub Actions / build-push

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "REACT_APP_GOOGLE_MAPS_API_KEY") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ARG REACT_APP_GOOGLE_MAPS_MAP_ID
ENV REACT_APP_GOOGLE_MAPS_MAP_ID=${REACT_APP_GOOGLE_MAPS_MAP_ID}

Expand All @@ -58,6 +57,8 @@

COPY --from=build-server /app/server/build /app/server/build
COPY --from=build-server /app/server/package.json /app/server/package.json
COPY --from=build-server /app/shared/build /app/shared/build
COPY --from=build-server /app/shared/package.json /app/shared/package.json

# Set production environment after build
ENV NODE_ENV=production
Expand Down
33 changes: 17 additions & 16 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {},
"dependencies": {
"@carriage-web/shared": "workspace:*"
},
"scripts": {
"dev": "react-scripts start",
"start": "react-scripts start",
"build": "react-scripts build",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
"type-check": "tsc --project tsconfig.json --pretty --noEmit",
"test": "react-scripts test",
"eject": "react-scripts eject"
Expand All @@ -32,18 +33,6 @@
]
},
"devDependencies": {
"@types/uuid": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"autoprefixer": "^10.4.21",
"eslint": "^8.56.0",
"eslint-config-prettier": "^8.10.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"postcss": "^8.5.6",
"prettier": "2.8.8",
"tailwindcss": "^3.4.17",
"@emotion/react": "^11.13.5",
"@emotion/styled": "^11.13.5",
"@googlemaps/markerclusterer": "^2.5.3",
Expand All @@ -63,17 +52,28 @@
"@types/react-dom": "^18.3.0",
"@types/react-router-dom": "^5.3.3",
"@types/react-router-hash-link": "^2.4.9",
"@types/uuid": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"@vis.gl/react-google-maps": "^1.4.0",
"addresser": "^1.1.20",
"autoprefixer": "^10.4.21",
"axios": "^1.12.0",
"classnames": "^2.5.1",
"crypto-js": "^4.2.0",
"date-fns": "^2.30.0",
"dayjs": "^1.11.19",
"env-cmd": "^10.1.0",
"eslint": "^8.56.0",
"eslint-config-prettier": "^8.10.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"focus-trap-react": "^10.2.3",
"jwt-decode": "^4.0.0",
"moment": "^2.30.1",
"postcss": "^8.5.6",
"prettier": "2.8.8",
"react": "^18.3.1",
"react-big-calendar": "^1.14.1",
"react-csv": "^2.2.2",
Expand All @@ -85,7 +85,8 @@
"react-scripts": "^5.0.1",
"react-select": "^5.8.1",
"reactjs-popup": "^2.0.6",
"uuid": "^13.0.0",
"typescript": "catalog:"
"tailwindcss": "^3.4.17",
"typescript": "catalog:",
"uuid": "^13.0.0"
}
}
2 changes: 1 addition & 1 deletion frontend/src/components/AddRideButton/AddRideButton.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import RideDetailsComponent from '../RideDetails/RideDetailsComponent';
import { createEmptyRide } from '../../util/modelFixtures';
import { RideType } from '../../types';
import { RideType } from '@carriage-web/shared/types/ride';
import { useRides } from '../../context/RidesContext';
import buttonStyles from '../../styles/button.module.css';

Expand Down
14 changes: 6 additions & 8 deletions frontend/src/components/AuthManager/AuthManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@ import Toast from '../ConfirmationToast/ConfirmationToast';

import AdminRoutes from '../../pages/Admin/Routes';
import RiderRoutes from '../../pages/Rider/Routes';
import {
Admin,
Rider,
UnregisteredUser,
DriverType as Driver,
} from '../../types/index';
import { UnregisteredUserType } from '@carriage-web/shared/types';
import { RiderType } from '@carriage-web/shared/types/rider';
import { AdminType } from '@carriage-web/shared/types/admin';
import { DriverType } from '@carriage-web/shared/types/driver';
import DriverRoutes from '../../pages/Driver/Routes';
import { ToastStatus, useToast } from '../../context/toastContext';
import { createPortal } from 'react-dom';
Expand All @@ -49,14 +47,14 @@ export const decrypt = (hash: string | CryptoJS.lib.CipherParams) => {
const AuthManager = () => {
const [signedIn, setSignedIn] = useState(getCookie('jwt'));
const [id, setId] = useState(localStorage.getItem('userId') || '');
const [user, setUser] = useState<Rider | Admin | Driver>(
const [user, setUser] = useState<RiderType | AdminType | DriverType>(
JSON.parse(localStorage.getItem('user') || '{}')
);
const [refreshUser, setRefreshUser] = useState(() =>
createRefresh(id, localStorage.getItem('userType') || '', jwtValue())
);
const [unregisteredUser, setUnregisteredUser] =
useState<UnregisteredUser | null>(null);
useState<UnregisteredUserType | null>(null);
const [ssoError, setSsoError] = useState<string>('');

const navigate = useNavigate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ import {
import CloseIcon from '@mui/icons-material/Close';
import PhoneIcon from '@mui/icons-material/Phone';
import EmailIcon from '@mui/icons-material/Email';
import { Rider } from '../../types';
import { RiderType } from '@carriage-web/shared/types/rider';

interface ContactInfoModalProps {
open: boolean;
onClose: () => void;
rider: Rider | undefined;
rider: RiderType | undefined;
}

const ContactInfoModal: React.FC<ContactInfoModalProps> = ({
Expand Down
9 changes: 5 additions & 4 deletions frontend/src/components/EmployeeCards/EmployeeCards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { useNavigate } from 'react-router-dom';
import Card, { CardInfo } from '../Card/Card';
import styles from './employeecards.module.css';
import { phone, wheel, user } from '../../icons/userInfo/index';
import { Admin, Driver } from '../../types';
import { AdminType } from '@carriage-web/shared/types/admin';
import { DriverType } from '@carriage-web/shared/types/driver';

const formatPhone = (phoneNumber: string | undefined) => {
if (phoneNumber !== undefined) {
Expand All @@ -16,13 +17,13 @@ const formatPhone = (phoneNumber: string | undefined) => {
}
};

type Employee = Admin | Driver;
type Employee = AdminType | DriverType;

function isAdmin(employee: Employee): employee is Admin {
function isAdmin(employee: Employee): employee is AdminType {
return 'isDriver' in employee;
}

function isDriver(employee: Employee): employee is Driver {
function isDriver(employee: Employee): employee is DriverType {
return 'availability' in employee && !('isDriver' in employee);
}

Expand Down
1 change: 0 additions & 1 deletion frontend/src/components/ExportPreview/ExportPreview.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useState, useRef } from 'react';
import { CSVLink } from 'react-csv';
import ScheduledTable from '../UserTables/ScheduledTable';
import { Driver } from '../../types/index';
import styles from './exportPreview.module.css';
import { useEmployees } from '../../context/EmployeesContext';
import ExportButton from '../ExportButton/ExportButton';
Expand Down
9 changes: 5 additions & 4 deletions frontend/src/components/LocationModal/LocationModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ import { parseAddress } from 'addresser';
import { ToastStatus, useToast } from '../../context/toastContext';
import React, { useState } from 'react';
import { useForm, SubmitHandler } from 'react-hook-form';
import { Location, ObjectType, Tag } from '../../types/index';
import { ObjectType, Tag } from '../../types/index';
import { LocationType } from '@carriage-web/shared/types/location';
import { Button, Input, Label } from '../FormElements/FormElements';
import Modal from '../Modal/Modal';
import styles from './locationmodal.module.css';
import axios from '../../util/axios';

type LocationModalProps = {
existingLocation?: Location;
onAddLocation?: (newLocation: Location) => void;
onEditLocation?: (editedLocation: Location) => void;
existingLocation?: LocationType;
onAddLocation?: (newLocation: LocationType) => void;
onEditLocation?: (editedLocation: LocationType) => void;
};

type FormData = {
Expand Down
12 changes: 7 additions & 5 deletions frontend/src/components/Locations/LocationDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,20 @@ import {
import CloseIcon from '@mui/icons-material/Close';
import EditIcon from '@mui/icons-material/Edit';
import { LocationFormModal } from './LocationFormModal';
import { Location } from 'types';
import { LocationType } from '@carriage-web/shared/types/location';
import PaginatedImageCarousel from './ImageCarousel';
import { LocationImage } from './LocationImagesUpload';

interface Props {
location: (Location & { imagesList?: LocationImage[] }) | null;
location: (LocationType & { imagesList?: LocationImage[] }) | null;
onClose: () => void;
onSave: (loc: Location & { imagesList?: LocationImage[] }) => void;
onSave: (loc: LocationType & { imagesList?: LocationImage[] }) => void;
}

const LocationDialog: React.FC<Props> = ({ location, onClose, onSave }) => {
const [edit, setEdit] = useState(false);
const [current, setCurrent] = useState<
(Location & { imagesList?: LocationImage[] }) | null
(LocationType & { imagesList?: LocationImage[] }) | null
>(null);
const [images, setImages] = useState<LocationImage[]>([]);

Expand All @@ -51,7 +51,9 @@ const LocationDialog: React.FC<Props> = ({ location, onClose, onSave }) => {

if (!location || !current) return null;

const handleEditSave = (upd: Location & { imagesList?: LocationImage[] }) => {
const handleEditSave = (
upd: LocationType & { imagesList?: LocationImage[] }
) => {
onSave(upd);
setCurrent(upd);

Expand Down
13 changes: 7 additions & 6 deletions frontend/src/components/Locations/LocationFormModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import { APIProvider } from '@vis.gl/react-google-maps';
import LocationPickerMap from './LocationMapPicker';
import PlacesSearch from './PlacesSearch';
import GeocoderService from './GeocoderService';
import { Location, Tag } from 'types';
import { Tag } from 'types';
import { LocationType } from '@carriage-web/shared/types/location';
import styles from './locations.module.css';
import LocationImagesUpload, { LocationImage } from './LocationImagesUpload';

Expand All @@ -38,8 +39,8 @@ const CAMPUS_OPTIONS = [
interface Props {
open: boolean;
onClose: () => void;
onSubmit: (loc: Location & { imagesList?: LocationImage[] }) => void;
initialData?: Location & { imagesList?: LocationImage[] };
onSubmit: (loc: LocationType & { imagesList?: LocationImage[] }) => void;
initialData?: LocationType & { imagesList?: LocationImage[] };
mode: 'add' | 'edit';
}

Expand All @@ -50,7 +51,7 @@ export const LocationFormModal: React.FC<Props> = ({
initialData,
mode,
}) => {
const EMPTY: Location = {
const EMPTY: LocationType = {
id: '',
name: '',
shortName: '',
Expand All @@ -62,7 +63,7 @@ export const LocationFormModal: React.FC<Props> = ({
photoLink: '',
};

const [form, setForm] = useState<Location>(EMPTY);
const [form, setForm] = useState<LocationType>(EMPTY);
const [mapKey, setMapKey] = useState(0);
const [loadingAddr, setLoadingAddr] = useState(false);
const [error, setError] = useState<string | null>(null);
Expand All @@ -85,7 +86,7 @@ export const LocationFormModal: React.FC<Props> = ({
}
}, [open, initialData, mode]);

const update = (patch: Partial<Location>) =>
const update = (patch: Partial<LocationType>) =>
setForm((prev) => ({ ...prev, ...patch }));

const selectPoint = (lat: number, lng: number) => update({ lat, lng });
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/components/Locations/LocationMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import { MarkerClusterer } from '@googlemaps/markerclusterer';
import type { Marker } from '@googlemaps/markerclusterer';
import { OpenInFull } from '@mui/icons-material';
import styles from './locations.module.css';
import { Location } from 'types';
import { LocationType } from '@carriage-web/shared/types/location';

interface LocationMapProps {
locations: Location[];
selectedLocation: Location | null;
onLocationSelect: (location: Location | null) => void;
onViewDetails: (location: Location) => void;
locations: LocationType[];
selectedLocation: LocationType | null;
onLocationSelect: (location: LocationType | null) => void;
onViewDetails: (location: LocationType) => void;
}

/* -------------------------------------------------------------------------- */
Expand Down
Loading
Loading