Skip to content
This repository has been archived by the owner on Dec 10, 2024. It is now read-only.

Commit

Permalink
feat(activity): venue map (wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
jhdcruz committed Nov 29, 2024
1 parent 28fc2df commit 336264f
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 12 deletions.
Binary file modified bun.lockb
Binary file not shown.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"@mantine/notifications": "7.14.3",
"@mantine/spotlight": "7.14.3",
"@mantine/tiptap": "7.14.3",
"@mapbox/mapbox-gl-geocoder": "5.0.3",
"@next/bundle-analyzer": "15.0.3",
"@noble/ciphers": "1.1.2",
"@noble/hashes": "1.6.1",
Expand All @@ -67,6 +68,7 @@
"blob-util": "2.0.2",
"dayjs": "1.11.13",
"framer-motion": "11.12.0",
"mapbox-gl": "3.8.0",
"next": "15.0.4-canary.31",
"openai": "4.73.1",
"pdf-lib": "1.17.1",
Expand All @@ -83,6 +85,7 @@
"@eslint/eslintrc": "3.2.0",
"@eslint/js": "9.14.0",
"@million/lint": "^1.0.13",
"@types/mapbox__mapbox-gl-geocoder": "5.0.0",
"@types/node": "22.10.1",
"@types/qrcode": "1.5.5",
"@types/react": "18.3.12",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
IconCheck,
IconEdit,
IconEditOff,
IconExclamationCircle,
IconInbox,
IconInboxOff,
IconQrcode,
Expand Down Expand Up @@ -314,6 +315,22 @@ function ActivityDetailsHeader({
</Group>
)}

{activity?.venue && (
<Group mb="xs">
<Text c="dimmed">Venue:</Text>
<Anchor
href={`https://www.google.com/maps/search/${activity.venue.replace(/ /g, '+')}`}
target="_blank"
>
{activity.venue}
</Anchor>

<Tooltip label="Link might be inaccurate" withArrow>
<IconExclamationCircle size={18} />
</Tooltip>
</Group>
)}

{activity?.series && (
<Group mb="xs">
<Text c="dimmed">Series:</Text>
Expand Down Expand Up @@ -453,6 +470,7 @@ function ActivityDetailsHeader({
setSubscribed,
)
}
type="button"
variant={subscribed ? 'default' : 'filled'}
>
{subscribed ? 'Unsubscribe' : 'Subscribe'}
Expand Down
30 changes: 30 additions & 0 deletions src/app/portal/activities/_components/Forms/ActivityFormModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
} from '@mantine/dates';
import { isNotEmpty, useForm } from '@mantine/form';
import { notifications } from '@mantine/notifications';
import dynamic from 'next/dynamic';
import {
IconCheck,
IconUpload,
Expand All @@ -42,16 +43,26 @@ import {
import type { Tables, Enums } from '@/libs/supabase/_database';
import { getActivitiesInRange } from '@/libs/supabase/api/activity';
import { submitActivity } from '@portal/activities/actions';
import { PageLoader } from '@/components/Loader/PageLoader';
import { SeriesInput } from './SeriesInput';
import { listDepts } from '@/utils/user-types';
import { getDeptColor } from '@/utils/colors';
import classes from '@/styles/forms/ContainedInput.module.css';
import dayjs from '@/libs/dayjs';

const MapboxGeocoder = dynamic(
() => import('./MapboxGeocoder').then((mod) => mod.MapboxGeocoder),
{
loading: () => <PageLoader />,
ssr: false,
},
);

export interface ActivityFormProps {
id?: string;
title: string;
visibility: Enums<'activity_visibility'>;
venue?: [number, number];
image_url?: FileWithPath | string;
series?: string | null;
date_starting: DateValue;
Expand Down Expand Up @@ -92,6 +103,10 @@ export const ActivityFormModal = memo(
? URL.createObjectURL(coverFile[0])
: null;

const [venue, setVenue] = useState<[number, number]>([
120.98851163771423, 14.595059433301486,
]);

// form submission
const form = useForm<ActivityFormProps>({
mode: 'uncontrolled',
Expand Down Expand Up @@ -206,6 +221,12 @@ export const ActivityFormModal = memo(
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activity]);

// set venue
useEffect(() => {
form.setFieldValue('venue', venue);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [venue]);

return (
<Modal
key={activity?.id ?? 'new'}
Expand Down Expand Up @@ -367,6 +388,15 @@ export const ActivityFormModal = memo(

<Divider my="xs" />

<Input.Wrapper
description="Where will the activity take place?"
label="Activity Venue"
>
<MapboxGeocoder coordinates={venue} setCoordinates={setVenue} />
</Input.Wrapper>

<Divider my="xs" />

{/* Objectives and Outcomes */}
<Input.Wrapper
description="The activity's goals and objectives for its participants and partners."
Expand Down
96 changes: 96 additions & 0 deletions src/app/portal/activities/_components/Forms/MapboxGeocoder.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { useEffect, useRef, memo } from 'react';
import { Box } from '@mantine/core';
import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';

import MbGeocoder from '@mapbox/mapbox-gl-geocoder';
import '@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css';

export const MapboxGeocoder = memo(
({
coordinates,
setCoordinates,
}: {
/** lng, lat */
coordinates: [number, number];
setCoordinates: (coords: [number, number]) => void;
}) => {
const mapContainerRef = useRef<HTMLDivElement | null>(null);
const mapRef = useRef<mapboxgl.Map | null>(null);
const markerRef = useRef<mapboxgl.Marker | null>(null);

useEffect(() => {
if (!process.env.NEXT_PUBLIC_MAPBOX_PUBLIC) {
console.error('Mapbox public token is required');
} else {
mapboxgl.accessToken = process.env.NEXT_PUBLIC_MAPBOX_PUBLIC!;
}

if (mapContainerRef.current) {
// Define the bounding box for the Philippines
const philippinesBounds: [number, number, number, number] = [
116.87, 4.59, 126.59, 21.12,
];

mapRef.current = new mapboxgl.Map({
container: mapContainerRef.current,
style: 'mapbox://styles/mapbox/streets-v12',
localFontFamily: 'Inter',
zoom: 16,
maxBounds: philippinesBounds,
performanceMetricsCollection: false,
respectPrefersReducedMotion: true,
});

const geocoder = new MbGeocoder({
// @ts-expect-error - mapboxgl types are not updated
mapboxgl: mapboxgl,
accessToken: mapboxgl.accessToken,
countries: 'ph',
});

mapRef.current.addControl(geocoder);

// Add marker based on initial coordinates
markerRef.current = new mapboxgl.Marker({ draggable: true })
.setLngLat([coordinates[0], coordinates[1]])
.addTo(mapRef.current);

// Prevent map from panning when marker is dragged
markerRef.current.on('dragstart', () => {
mapRef.current!.dragPan.disable();
});

// Update coordinates when marker is dragged
markerRef.current.on('dragend', () => {
const lngLat = markerRef.current!.getLngLat();
setCoordinates([lngLat.lng, lngLat.lat]);
mapRef.current!.dragPan.enable();
});

// Update marker position when coordinates prop changes
mapRef.current.on('load', () => {
mapRef.current!.setCenter([coordinates[0], coordinates[1]]);
});
}

return () => {
if (mapRef.current) {
mapRef.current.remove();
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return (
<Box
className="rounded-md"
h={340}
id="editableMap"
ref={mapContainerRef}
w="100%"
/>
);
},
);
MapboxGeocoder.displayName = 'MapboxGeocoder';
2 changes: 2 additions & 0 deletions src/app/portal/activities/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export async function submitActivity(
series: seriesId,
date_ending: activity.date_ending?.toUTCString(),
date_starting: activity.date_starting?.toUTCString(),
venue: activity.venue,
created_by: session.user.id,
objectives: [
activity.objective_1?.trim() ?? '',
Expand All @@ -109,6 +110,7 @@ export async function submitActivity(
series: seriesId,
date_ending: activity.date_ending?.toUTCString(),
date_starting: activity.date_starting?.toUTCString(),
venue: activity.venue,
objectives: [
activity.objective_1?.trim() ?? '',
activity.objective_2?.trim() ?? '',
Expand Down
28 changes: 16 additions & 12 deletions src/libs/supabase/_database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export type Database = {
series: string | null
title: string
updated_at: string | null
venue: number[] | null
visibility: Database["public"]["Enums"]["activity_visibility"]
}
Insert: {
Expand All @@ -40,6 +41,7 @@ export type Database = {
series?: string | null
title: string
updated_at?: string | null
venue?: number[] | null
visibility?: Database["public"]["Enums"]["activity_visibility"]
}
Update: {
Expand All @@ -56,6 +58,7 @@ export type Database = {
series?: string | null
title?: string
updated_at?: string | null
venue?: number[] | null
visibility?: Database["public"]["Enums"]["activity_visibility"]
}
Relationships: [
Expand All @@ -64,14 +67,14 @@ export type Database = {
columns: ["created_by"]
isOneToOne: false
referencedRelation: "activities_faculties_view"
referencedColumns: ["referrer_id"]
referencedColumns: ["id"]
},
{
foreignKeyName: "events_created_by_fkey"
columns: ["created_by"]
isOneToOne: false
referencedRelation: "activities_faculties_view"
referencedColumns: ["id"]
referencedColumns: ["referrer_id"]
},
{
foreignKeyName: "events_created_by_fkey"
Expand Down Expand Up @@ -164,14 +167,14 @@ export type Database = {
columns: ["user_id"]
isOneToOne: false
referencedRelation: "activities_faculties_view"
referencedColumns: ["referrer_id"]
referencedColumns: ["id"]
},
{
foreignKeyName: "activity_feedback_user_id_fkey"
columns: ["user_id"]
isOneToOne: false
referencedRelation: "activities_faculties_view"
referencedColumns: ["id"]
referencedColumns: ["referrer_id"]
},
{
foreignKeyName: "activity_feedback_user_id_fkey"
Expand Down Expand Up @@ -304,14 +307,14 @@ export type Database = {
columns: ["user_id"]
isOneToOne: false
referencedRelation: "activities_faculties_view"
referencedColumns: ["referrer_id"]
referencedColumns: ["id"]
},
{
foreignKeyName: "participants_user_id_fkey"
columns: ["user_id"]
isOneToOne: false
referencedRelation: "activities_faculties_view"
referencedColumns: ["id"]
referencedColumns: ["referrer_id"]
},
{
foreignKeyName: "participants_user_id_fkey"
Expand Down Expand Up @@ -459,14 +462,14 @@ export type Database = {
columns: ["generated_by"]
isOneToOne: false
referencedRelation: "activities_faculties_view"
referencedColumns: ["referrer_id"]
referencedColumns: ["id"]
},
{
foreignKeyName: "certs_generated_by_fkey"
columns: ["generated_by"]
isOneToOne: false
referencedRelation: "activities_faculties_view"
referencedColumns: ["id"]
referencedColumns: ["referrer_id"]
},
{
foreignKeyName: "certs_generated_by_fkey"
Expand Down Expand Up @@ -543,14 +546,14 @@ export type Database = {
columns: ["user_id"]
isOneToOne: false
referencedRelation: "activities_faculties_view"
referencedColumns: ["referrer_id"]
referencedColumns: ["id"]
},
{
foreignKeyName: "event_handlers_user_id_fkey"
columns: ["user_id"]
isOneToOne: false
referencedRelation: "activities_faculties_view"
referencedColumns: ["id"]
referencedColumns: ["referrer_id"]
},
{
foreignKeyName: "event_handlers_user_id_fkey"
Expand All @@ -571,14 +574,14 @@ export type Database = {
columns: ["referrer"]
isOneToOne: false
referencedRelation: "activities_faculties_view"
referencedColumns: ["referrer_id"]
referencedColumns: ["id"]
},
{
foreignKeyName: "faculty_assignments_referrer_fkey"
columns: ["referrer"]
isOneToOne: false
referencedRelation: "activities_faculties_view"
referencedColumns: ["id"]
referencedColumns: ["referrer_id"]
},
{
foreignKeyName: "faculty_assignments_referrer_fkey"
Expand Down Expand Up @@ -679,6 +682,7 @@ export type Database = {
series_color: string | null
title: string | null
updated_at: string | null
venue: number[] | null
visibility: Database["public"]["Enums"]["activity_visibility"] | null
}
Relationships: []
Expand Down

0 comments on commit 336264f

Please sign in to comment.