diff --git a/bun.lock b/bun.lock index 94481cc..19408ab 100644 --- a/bun.lock +++ b/bun.lock @@ -11,10 +11,6 @@ "@radix-ui/react-separator": "^1.1.8", "@radix-ui/react-slot": "^1.2.4", "@t3-oss/env-nextjs": "^0.12.0", - "@tanstack/react-query": "^5.69.0", - "@trpc/client": "^11.0.0", - "@trpc/react-query": "^11.0.0", - "@trpc/server": "^11.0.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "leaflet": "^1.9.4", @@ -24,8 +20,6 @@ "react": "19.2.1", "react-dom": "19.2.1", "react-leaflet": "^5.0.0", - "server-only": "^0.0.1", - "superjson": "^2.2.1", "tailwind-merge": "^3.4.0", "zod": "^3.24.2", }, @@ -317,16 +311,6 @@ "@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.17", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.17", "@tailwindcss/oxide": "4.1.17", "postcss": "^8.4.41", "tailwindcss": "4.1.17" } }, "sha512-+nKl9N9mN5uJ+M7dBOOCzINw94MPstNR/GtIhz1fpZysxL/4a+No64jCBD6CPN+bIHWFx3KWuu8XJRrj/572Dw=="], - "@tanstack/query-core": ["@tanstack/query-core@5.90.12", "", {}, "sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg=="], - - "@tanstack/react-query": ["@tanstack/react-query@5.90.12", "", { "dependencies": { "@tanstack/query-core": "5.90.12" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-graRZspg7EoEaw0a8faiUASCyJrqjKPdqJ9EwuDRUF9mEYJ1YPczI9H+/agJ0mOJkPCJDk0lsz5QTrLZ/jQ2rg=="], - - "@trpc/client": ["@trpc/client@11.7.2", "", { "peerDependencies": { "@trpc/server": "11.7.2", "typescript": ">=5.7.2" } }, "sha512-OQxqUMfpDvjcszo9dbnqWQXnW2L5IbrKSz2H7l8s+mVM3EvYw7ztQ/gjFIN3iy0NcamiQfd4eE6qjcb9Lm+63A=="], - - "@trpc/react-query": ["@trpc/react-query@11.7.2", "", { "peerDependencies": { "@tanstack/react-query": "^5.80.3", "@trpc/client": "11.7.2", "@trpc/server": "11.7.2", "react": ">=18.2.0", "react-dom": ">=18.2.0", "typescript": ">=5.7.2" } }, "sha512-IcLDMqx2mvlGRxkr0/m37TtPvRQ8nonITH3EwYv436x0Igx8eduR9z4tdgGBsjJY9e5W1G7cZ4zKCwrizSimFQ=="], - - "@trpc/server": ["@trpc/server@11.7.2", "", { "peerDependencies": { "typescript": ">=5.7.2" } }, "sha512-AgB26PXY69sckherIhCacKLY49rxE2XP5h38vr/KMZTbLCL1p8IuIoKPjALTcugC2kbyQ7Lbqo2JDVfRSmPmfQ=="], - "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], @@ -479,8 +463,6 @@ "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - "copy-anything": ["copy-anything@4.0.5", "", { "dependencies": { "is-what": "^5.2.0" } }, "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA=="], - "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], @@ -701,8 +683,6 @@ "is-weakset": ["is-weakset@2.0.4", "", { "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ=="], - "is-what": ["is-what@5.5.0", "", {}, "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw=="], - "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], @@ -887,8 +867,6 @@ "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "server-only": ["server-only@0.0.1", "", {}, "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA=="], - "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], "set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="], @@ -933,8 +911,6 @@ "styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="], - "superjson": ["superjson@2.2.6", "", { "dependencies": { "copy-anything": "^4" } }, "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA=="], - "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], diff --git a/package.json b/package.json index 0e6e63e..c547f60 100644 --- a/package.json +++ b/package.json @@ -22,10 +22,6 @@ "@radix-ui/react-separator": "^1.1.8", "@radix-ui/react-slot": "^1.2.4", "@t3-oss/env-nextjs": "^0.12.0", - "@tanstack/react-query": "^5.69.0", - "@trpc/client": "^11.0.0", - "@trpc/react-query": "^11.0.0", - "@trpc/server": "^11.0.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "leaflet": "^1.9.4", @@ -35,8 +31,6 @@ "react": "19.2.1", "react-dom": "19.2.1", "react-leaflet": "^5.0.0", - "server-only": "^0.0.1", - "superjson": "^2.2.1", "tailwind-merge": "^3.4.0", "zod": "^3.24.2" }, diff --git a/public/images/shops/7th-st-cafe.jpg b/public/images/shops/7th-st-cafe.jpg new file mode 100644 index 0000000..12064e8 Binary files /dev/null and b/public/images/shops/7th-st-cafe.jpg differ diff --git a/public/images/shops/alee-s-cafe.jpg b/public/images/shops/alee-s-cafe.jpg new file mode 100644 index 0000000..86ef5ba Binary files /dev/null and b/public/images/shops/alee-s-cafe.jpg differ diff --git a/public/images/shops/all-star-bagels.jpg b/public/images/shops/all-star-bagels.jpg new file mode 100644 index 0000000..63973e9 Binary files /dev/null and b/public/images/shops/all-star-bagels.jpg differ diff --git a/public/images/shops/amami-kitchen.jpg b/public/images/shops/amami-kitchen.jpg new file mode 100644 index 0000000..a813ed0 Binary files /dev/null and b/public/images/shops/amami-kitchen.jpg differ diff --git a/public/images/shops/barnes-noble-caf.jpg b/public/images/shops/barnes-noble-caf.jpg new file mode 100644 index 0000000..b5c5b11 Binary files /dev/null and b/public/images/shops/barnes-noble-caf.jpg differ diff --git a/public/images/shops/cornerstone-kitchen.jpg b/public/images/shops/cornerstone-kitchen.jpg new file mode 100644 index 0000000..db19e5e Binary files /dev/null and b/public/images/shops/cornerstone-kitchen.jpg differ diff --git a/public/images/shops/culture-coffee.jpg b/public/images/shops/culture-coffee.jpg new file mode 100644 index 0000000..90793b3 Binary files /dev/null and b/public/images/shops/culture-coffee.jpg differ diff --git a/public/images/shops/cycleup-coffee.jpg b/public/images/shops/cycleup-coffee.jpg new file mode 100644 index 0000000..4b8690b Binary files /dev/null and b/public/images/shops/cycleup-coffee.jpg differ diff --git a/public/images/shops/dunkin.jpg b/public/images/shops/dunkin.jpg new file mode 100644 index 0000000..76b4916 Binary files /dev/null and b/public/images/shops/dunkin.jpg differ diff --git a/public/images/shops/gram-s-eatery.jpg b/public/images/shops/gram-s-eatery.jpg new file mode 100644 index 0000000..8b3affd Binary files /dev/null and b/public/images/shops/gram-s-eatery.jpg differ diff --git a/public/images/shops/panera-bread.jpg b/public/images/shops/panera-bread.jpg new file mode 100644 index 0000000..3efbfe2 Binary files /dev/null and b/public/images/shops/panera-bread.jpg differ diff --git a/public/images/shops/paris-bakery-caf.jpg b/public/images/shops/paris-bakery-caf.jpg new file mode 100644 index 0000000..295751c Binary files /dev/null and b/public/images/shops/paris-bakery-caf.jpg differ diff --git a/public/images/shops/starbucks-coffee.jpg b/public/images/shops/starbucks-coffee.jpg new file mode 100644 index 0000000..72f0866 Binary files /dev/null and b/public/images/shops/starbucks-coffee.jpg differ diff --git a/public/images/shops/starbucks-giant.jpg b/public/images/shops/starbucks-giant.jpg new file mode 100644 index 0000000..eca81e8 Binary files /dev/null and b/public/images/shops/starbucks-giant.jpg differ diff --git a/public/images/shops/tastecraft-cafe.jpg b/public/images/shops/tastecraft-cafe.jpg new file mode 100644 index 0000000..c2086a4 Binary files /dev/null and b/public/images/shops/tastecraft-cafe.jpg differ diff --git a/src/app/api/trpc/[trpc]/route.ts b/src/app/api/trpc/[trpc]/route.ts deleted file mode 100644 index f41a82e..0000000 --- a/src/app/api/trpc/[trpc]/route.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; -import { type NextRequest } from "next/server"; - -import { env } from "~/env"; -import { appRouter } from "~/server/api/root"; -import { createTRPCContext } from "~/server/api/trpc"; - -/** - * This wraps the `createTRPCContext` helper and provides the required context for the tRPC API when - * handling a HTTP request (e.g. when you make requests from Client Components). - */ -const createContext = async (req: NextRequest) => { - return createTRPCContext({ - headers: req.headers, - }); -}; - -const handler = (req: NextRequest) => - fetchRequestHandler({ - endpoint: "/api/trpc", - req, - router: appRouter, - createContext: () => createContext(req), - onError: - env.NODE_ENV === "development" - ? ({ path, error }) => { - console.error( - `❌ tRPC failed on ${path ?? ""}: ${error.message}`, - ); - } - : undefined, - }); - -export { handler as GET, handler as POST }; diff --git a/src/app/layout.tsx b/src/app/layout.tsx index e225238..c08fc77 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -3,7 +3,6 @@ import "~/styles/globals.css"; import { type Metadata } from "next"; import { PT_Serif } from "next/font/google"; -import { TRPCReactProvider } from "~/trpc/react"; import { ThemeProvider } from "~/components/ThemeProvider"; export const metadata: Metadata = { @@ -30,7 +29,7 @@ export default function RootLayout({ enableSystem disableTransitionOnChange > - {children} + {children} diff --git a/src/components/Drawer.tsx b/src/components/Drawer.tsx index a86c84d..b196efc 100644 --- a/src/components/Drawer.tsx +++ b/src/components/Drawer.tsx @@ -43,7 +43,13 @@ export default function Drawer({ shop, onClose }: DrawerProps) { {/* Header Image */}
{imageLoading && ( -
+
diff --git a/src/components/MapLoader.tsx b/src/components/MapLoader.tsx index 6cb750d..3105876 100644 --- a/src/components/MapLoader.tsx +++ b/src/components/MapLoader.tsx @@ -22,8 +22,9 @@ interface CoffeeShop { interface MapLoaderProps { shops: CoffeeShop[]; onShopSelect: (shop: CoffeeShop) => void; + selectedShop: CoffeeShop | null; } -export default function MapLoader({ shops, onShopSelect }: MapLoaderProps) { - return ; +export default function MapLoader({ shops, onShopSelect, selectedShop }: MapLoaderProps) { + return ; } diff --git a/src/lib/data.ts b/src/lib/data.ts index 270ecb9..293d4dd 100644 --- a/src/lib/data.ts +++ b/src/lib/data.ts @@ -8,7 +8,7 @@ export const COFFEE_SHOPS = [ address: "103 S 6th St, Lewisburg, PA 17837", phone: "(570) 490-7857", website: "https://www.amamiespresso.com", - image: "https://dynamic-media-cdn.tripadvisor.com/media/photo-o/24/e0/57/64/we-can-t-wait-to-serve.jpg?w=500&h=-1&s=1" + image: "/images/shops/amami-kitchen.jpg" }, { id: 2, @@ -19,7 +19,7 @@ export const COFFEE_SHOPS = [ address: "216 St. John St, Lewisburg, PA 17837", phone: "(570) 601-7903", website: "https://www.instagram.com/culturecoffeee_", - image: "https://lh3.googleusercontent.com/gps-cs-s/AG0ilSwqBStEoCw_piT-LQMybbAZJLcYVBjASVbNNyl6F5uazGR8Bs9DLvZrijlhg-8q5h1cDhRU6sOnXkRXCljQAFMgMKhATMm0j7tlleitpX75jm61vlHl6dJJ5GQHbrYxOqaNiyl5sw=s1360-w1360-h1020-rw" + image: "/images/shops/culture-coffee.jpg" }, { id: 3, @@ -30,7 +30,7 @@ export const COFFEE_SHOPS = [ address: "420 S 7th St, Lewisburg, PA 17837", phone: "(570) 577-1240", website: "https://www.bucknell.edu/life-bucknell/dining-services/places-eat", - image: "https://www.bucknell.edu/sites/default/files/styles/wysiwyg_left_right/public/libris/C00001GOQFVeT0YE/G0000Szz5oTniLSw/247thStreetCafe002.jpg" + image: "/images/shops/7th-st-cafe.jpg" }, { id: 4, @@ -41,7 +41,7 @@ export const COFFEE_SHOPS = [ address: "512 Market St, Lewisburg, PA 17837", phone: "(570) 768-5340", website: "https://www.tastecraftcafe.com", - image: "https://s3-media0.fl.yelpcdn.com/bphoto/x_plvYaNq4hWJcBm5VAmxA/348s.jpg" + image: "/images/shops/tastecraft-cafe.jpg" }, { id: 5, @@ -52,7 +52,7 @@ export const COFFEE_SHOPS = [ address: "335 Market St, Lewisburg, PA 17837", phone: "(570) 884-2138", website: "https://parisbakery.cafe", - image: "https://lh3.googleusercontent.com/gps-cs-s/AG0ilSzM-rGl_-KGgtp5l6H7-7_x6d_JovpFXsHDonjdHCTCG6-1xslBf0by3-O1FuNyvhTVx7v7JujiiF6WhnKR1xFxFJmEuQMYPn5C0tC6KysPegZdGTQAJ81aBupHvxmnBMA0dzhr5v3dIeU=w408-h544-k-no" + image: "/images/shops/paris-bakery-caf.jpg" }, { id: 6, @@ -63,7 +63,7 @@ export const COFFEE_SHOPS = [ address: "429 Market St, Lewisburg, PA 17837", phone: "(570) 413-1705", website: "https://www.cycleupcafe.com", - image: "https://lh3.googleusercontent.com/p/AF1QipPuvWYqs_ApxBUQrTFWB8qujODjIuihtQU8-ceO=w408-h408-k-no" + image: "/images/shops/cycleup-coffee.jpg" }, { id: 7, @@ -74,7 +74,7 @@ export const COFFEE_SHOPS = [ address: "120 Hardwood Dr, Lewisburg, PA 17837", phone: "(570) 556-4191", website: "https://millercenterlewisburg.com/cornerstone-kitchen", - image: "https://lh3.googleusercontent.com/p/AF1QipM0qi8mIvgz0xz5xM1rOsN_WgNJoaetFyHX9DbW=w408-h271-k-no" + image: "/images/shops/cornerstone-kitchen.jpg" }, { id: 8, @@ -85,7 +85,7 @@ export const COFFEE_SHOPS = [ address: "21 N 3rd St, Lewisburg, PA 17837", phone: "(570) 522-0230", website: "https://www.facebook.com/gramseaterylewisburg", - image: "data:image/jpeg;base64,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" + image: "/images/shops/gram-s-eatery.jpg" }, { id: 9, @@ -96,7 +96,7 @@ export const COFFEE_SHOPS = [ address: "7431 Westbranch Hwy, Lewisburg, PA 17837", phone: "(570) 452-2370", website: "https://www.starbucks.com/store-locator/store/1010326/", - image: "https://lh3.googleusercontent.com/gps-cs-s/AG0ilSwoWeA6luV_AXP4W4SM7ztQbT13LTEtDu7kGXfSD1QH1aSDqh7gtVms5xwrpn8hnlH7Pl6XKaHe8zlmjkYJNFHJpn-X3baMu6m82hKbC-lr32-ZJlZleRImtGyfM3jqf981gSD1QA=w408-h313-k-no" + image: "/images/shops/starbucks-coffee.jpg" }, { id: 10, @@ -107,7 +107,7 @@ export const COFFEE_SHOPS = [ address: "400 Market St, Lewisburg, PA 17837", phone: "(570) 577-3960", website: "https://bucknell.bncollege.com", - image: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ2UsV1D3Wb9yjMc1q5fYSdWOIrOW8ds3yWQQ&s" + image: "/images/shops/barnes-noble-caf.jpg" }, { id: 11, @@ -118,7 +118,7 @@ export const COFFEE_SHOPS = [ address: "224 Hardwood Dr, Lewisburg, PA 17837", phone: "(570) 523-3200", website: "https://www.starbucks.com", - image: "https://lh3.googleusercontent.com/gps-cs-s/AG0ilSzCd6SQk2u5f4FRR6mhxlERZnBhdEJz3MO8Ag46laO_WtCVvpjP4l8qQWGXWJrevMXrYDfXjgDX1IwWj5S_LSq3Y1C3CKz7EIgOC5w4xNa8ha1U-43akkk29BbDBnRuLql3vHxs=w426-h240-k-no" + image: "/images/shops/starbucks-giant.jpg" }, { id: 12, @@ -129,7 +129,7 @@ export const COFFEE_SHOPS = [ address: "600 N Derr Dr, Lewisburg, PA 17837", phone: "(570) 524-4900", website: "https://www.dunkindonuts.com", - image: "https://bloximages.newyork1.vip.townnews.com/northcentralpa.com/content/tncms/assets/v3/editorial/2/87/2872aa54-5fab-11eb-9cb0-53994a2d0d92/600fc9c4b9859.image.jpg?resize=400%2C232" + image: "/images/shops/dunkin.jpg" }, { id: 13, @@ -140,7 +140,7 @@ export const COFFEE_SHOPS = [ address: "232 Market St, Lewisburg, PA 17837", phone: "(570) 523-1234", website: "https://www.aleescafe.com", - image: "https://lh3.googleusercontent.com/gps-cs-s/AG0ilSxIioeto4uWiEpFm3qEnXLU4laa3pTZdOUGr6_flBF9kQlWFrb6v3ups69t_qyhY-bSE55-kyWAfY3ZXvrbdk24zi1Xd9Xps59G79H_f1O9JzqQJjcYgJ2_njO3Z8xdDDGH8MeOOA=w408-h306-k-no" + image: "/images/shops/alee-s-cafe.jpg" }, { id: 14, @@ -151,7 +151,7 @@ export const COFFEE_SHOPS = [ address: "300 Market St, Lewisburg, PA 17837", phone: "(570) 524-1000", website: "https://www.allstarbagels.com", - image: "https://lh3.googleusercontent.com/gps-cs-s/AG0ilSzKYY7aKCpG3VEhSbARvMGrpG7RN9f2bxp6o2hDEFGJhfm6xKyfApSQyUXXuwYabZ_L9tiY53dIlYSTUM7RZYa1CfETIeJoZmg0CrBinuJtv-rFZ7cZm6h3SG1GLW5xXh5lnpZn8Q=w289-h312-n-k-no" + image: "/images/shops/all-star-bagels.jpg" }, { id: 15, @@ -162,6 +162,6 @@ export const COFFEE_SHOPS = [ address: "6951 Westbranch Hwy, Lewisburg, PA 17837", phone: "(570) 524-0000", website: "https://www.panerabread.com", - image: "https://lh3.googleusercontent.com/gps-cs-s/AG0ilSyhOMySh1UtEKrVAepRZZBlHOrUueXrDvPRmZvqw11zTNxe51G4q2cdmg_jeGJj_itjkj6kcS6byOPw_RF5y8Lab7RWoYtkX-betKDaKKsuAYYDlyWtC2h2kQV8WhYW0jivtt3TCJbJk0w=w408-h306-k-no" + image: "/images/shops/panera-bread.jpg" } ]; \ No newline at end of file diff --git a/src/server/api/root.ts b/src/server/api/root.ts deleted file mode 100644 index b341fc4..0000000 --- a/src/server/api/root.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { postRouter } from "~/server/api/routers/post"; -import { createCallerFactory, createTRPCRouter } from "~/server/api/trpc"; - -/** - * This is the primary router for your server. - * - * All routers added in /api/routers should be manually added here. - */ -export const appRouter = createTRPCRouter({ - post: postRouter, -}); - -// export type definition of API -export type AppRouter = typeof appRouter; - -/** - * Create a server-side caller for the tRPC API. - * @example - * const trpc = createCaller(createContext); - * const res = await trpc.post.all(); - * ^? Post[] - */ -export const createCaller = createCallerFactory(appRouter); diff --git a/src/server/api/routers/post.ts b/src/server/api/routers/post.ts deleted file mode 100644 index afe46d8..0000000 --- a/src/server/api/routers/post.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { z } from "zod"; - -import { createTRPCRouter, publicProcedure } from "~/server/api/trpc"; - -// Mocked DB -interface Post { - id: number; - name: string; -} -const posts: Post[] = [ - { - id: 1, - name: "Hello World", - }, -]; - -export const postRouter = createTRPCRouter({ - hello: publicProcedure - .input(z.object({ text: z.string() })) - .query(({ input }) => { - return { - greeting: `Hello ${input.text}`, - }; - }), - - create: publicProcedure - .input(z.object({ name: z.string().min(1) })) - .mutation(async ({ input }) => { - const post: Post = { - id: posts.length + 1, - name: input.name, - }; - posts.push(post); - return post; - }), - - getLatest: publicProcedure.query(() => { - return posts.at(-1) ?? null; - }), -}); diff --git a/src/server/api/trpc.ts b/src/server/api/trpc.ts deleted file mode 100644 index 5385e26..0000000 --- a/src/server/api/trpc.ts +++ /dev/null @@ -1,99 +0,0 @@ -/** - * YOU PROBABLY DON'T NEED TO EDIT THIS FILE, UNLESS: - * 1. You want to modify request context (see Part 1). - * 2. You want to create a new middleware or type of procedure (see Part 3). - * - * TL;DR - This is where all the tRPC server stuff is created and plugged in. The pieces you will - * need to use are documented accordingly near the end. - */ -import { initTRPC } from "@trpc/server"; -import superjson from "superjson"; -import { ZodError } from "zod"; - -/** - * 1. CONTEXT - * - * This section defines the "contexts" that are available in the backend API. - * - * These allow you to access things when processing a request, like the database, the session, etc. - * - * This helper generates the "internals" for a tRPC context. The API handler and RSC clients each - * wrap this and provides the required context. - * - * @see https://trpc.io/docs/server/context - */ -export const createTRPCContext = async (opts: { headers: Headers }) => { - return { - ...opts, - }; -}; - -/** - * 2. INITIALIZATION - * - * This is where the tRPC API is initialized, connecting the context and transformer. We also parse - * ZodErrors so that you get typesafety on the frontend if your procedure fails due to validation - * errors on the backend. - */ -const t = initTRPC.context().create({ - transformer: superjson, - errorFormatter({ shape, error }) { - return { - ...shape, - data: { - ...shape.data, - zodError: - error.cause instanceof ZodError ? error.cause.flatten() : null, - }, - }; - }, -}); - -/** - * Create a server-side caller. - * - * @see https://trpc.io/docs/server/server-side-calls - */ -export const createCallerFactory = t.createCallerFactory; - -/** - * 3. ROUTER & PROCEDURE (THE IMPORTANT BIT) - * - * These are the pieces you use to build your tRPC API. You should import these a lot in the - * "/src/server/api/routers" directory. - */ - -/** - * This is how you create new routers and sub-routers in your tRPC API. - * - * @see https://trpc.io/docs/router - */ -export const createTRPCRouter = t.router; - -/** - * Middleware for timing procedure execution and adding an artificial delay. - * - * You can remove this if you don't want to do it. - */ -const timingMiddleware = t.middleware(async ({ next }) => { - if (t._config.isDev) { - // artificial delay in dev 100-500ms - const waitMs = Math.floor(Math.random() * 400) + 100; - await new Promise((resolve) => setTimeout(resolve, waitMs)); - } - const result = await next(); - if (t._config.isDev) { - // const durationMs = Date.now() - start; - // console.log(`[TRPC] ${path} took ${durationMs}ms to execute`); - } - return result; -}); - -/** - * Public (unauthenticated) procedure - * - * This is the base piece you use to build new queries and mutations on your tRPC API. It does not - * guarantee that a user querying is authorized, but you can still access user session data if they - * are logged in. - */ -export const publicProcedure = t.procedure.use(timingMiddleware); diff --git a/src/trpc/query-client.ts b/src/trpc/query-client.ts deleted file mode 100644 index bda6439..0000000 --- a/src/trpc/query-client.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { - defaultShouldDehydrateQuery, - QueryClient, -} from "@tanstack/react-query"; -import SuperJSON from "superjson"; - -export const createQueryClient = () => - new QueryClient({ - defaultOptions: { - queries: { - // With SSR, we usually want to set some default staleTime - // above 0 to avoid refetching immediately on the client - staleTime: 30 * 1000, - }, - dehydrate: { - serializeData: SuperJSON.serialize, - shouldDehydrateQuery: (query) => - defaultShouldDehydrateQuery(query) || - query.state.status === "pending", - }, - hydrate: { - deserializeData: SuperJSON.deserialize, - }, - }, - }); diff --git a/src/trpc/react.tsx b/src/trpc/react.tsx deleted file mode 100644 index 37a8002..0000000 --- a/src/trpc/react.tsx +++ /dev/null @@ -1,78 +0,0 @@ -"use client"; - -import { QueryClientProvider, type QueryClient } from "@tanstack/react-query"; -import { httpBatchStreamLink, loggerLink } from "@trpc/client"; -import { createTRPCReact } from "@trpc/react-query"; -import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server"; -import { useState } from "react"; -import SuperJSON from "superjson"; - -import { type AppRouter } from "~/server/api/root"; -import { createQueryClient } from "./query-client"; - -let clientQueryClientSingleton: QueryClient | undefined = undefined; -const getQueryClient = () => { - if (typeof window === "undefined") { - // Server: always make a new query client - return createQueryClient(); - } - // Browser: use singleton pattern to keep the same query client - clientQueryClientSingleton ??= createQueryClient(); - - return clientQueryClientSingleton; -}; - -export const api = createTRPCReact(); - -/** - * Inference helper for inputs. - * - * @example type HelloInput = RouterInputs['example']['hello'] - */ -export type RouterInputs = inferRouterInputs; - -/** - * Inference helper for outputs. - * - * @example type HelloOutput = RouterOutputs['example']['hello'] - */ -export type RouterOutputs = inferRouterOutputs; - -export function TRPCReactProvider(props: { children: React.ReactNode }) { - const queryClient = getQueryClient(); - - const [trpcClient] = useState(() => - api.createClient({ - links: [ - loggerLink({ - enabled: (op) => - process.env.NODE_ENV === "development" || - (op.direction === "down" && op.result instanceof Error), - }), - httpBatchStreamLink({ - transformer: SuperJSON, - url: getBaseUrl() + "/api/trpc", - headers: () => { - const headers = new Headers(); - headers.set("x-trpc-source", "nextjs-react"); - return headers; - }, - }), - ], - }), - ); - - return ( - - - {props.children} - - - ); -} - -function getBaseUrl() { - if (typeof window !== "undefined") return window.location.origin; - if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; - return `http://localhost:${process.env.PORT ?? 3000}`; -} diff --git a/src/trpc/server.ts b/src/trpc/server.ts deleted file mode 100644 index 9e72cbe..0000000 --- a/src/trpc/server.ts +++ /dev/null @@ -1,30 +0,0 @@ -import "server-only"; - -import { createHydrationHelpers } from "@trpc/react-query/rsc"; -import { headers } from "next/headers"; -import { cache } from "react"; - -import { createCaller, type AppRouter } from "~/server/api/root"; -import { createTRPCContext } from "~/server/api/trpc"; -import { createQueryClient } from "./query-client"; - -/** - * This wraps the `createTRPCContext` helper and provides the required context for the tRPC API when - * handling a tRPC call from a React Server Component. - */ -const createContext = cache(async () => { - const heads = new Headers(await headers()); - heads.set("x-trpc-source", "rsc"); - - return createTRPCContext({ - headers: heads, - }); -}); - -const getQueryClient = cache(createQueryClient); -const caller = createCaller(createContext); - -export const { trpc: api, HydrateClient } = createHydrationHelpers( - caller, - getQueryClient, -);