diff --git a/javascript/nextjs/tables/.gitignore b/javascript/nextjs/tables/.gitignore new file mode 100644 index 0000000..5ef6a52 --- /dev/null +++ b/javascript/nextjs/tables/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/javascript/nextjs/tables/README.md b/javascript/nextjs/tables/README.md new file mode 100644 index 0000000..e215bc4 --- /dev/null +++ b/javascript/nextjs/tables/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/javascript/nextjs/tables/app/components/BasicTable.tsx b/javascript/nextjs/tables/app/components/BasicTable.tsx new file mode 100644 index 0000000..518e98a --- /dev/null +++ b/javascript/nextjs/tables/app/components/BasicTable.tsx @@ -0,0 +1,121 @@ +'use client' +import { useState } from "react"; +import { ChevronDown, ChevronUp } from "lucide-react"; + +const DESCENDING = "desc" +const ASCENDING = "asc" + +const getTableHeader = (column, sortField, sortDirection) => { + let columnValue = column.name + // TODO: If any columns can't be sorted the cursor should be cursor-not-allowed + let defaultClassName = "flex justify-center space-x-2 cursor-pointer" + if(column.key == sortField && sortDirection == DESCENDING){ + return ( +
+ {column.name} +
+ ) + }else if(column.key == sortField && sortDirection == ASCENDING){ + return ( +
+
+ {column.name} +
+ +
+ ) + } + return ( +
+ {column.name} +
+ ) +} + +const BasicTable = ({columns, data}) => { + // console.log(`Data = ${JSON.stringify(data)}`) + // const rows = data.forEach((entry, idx) => { + // return + // }) + // const [cursorColumn, setCursorColumn] = useState("") + const [tableData, setTableData] = useState(data) + const [sortDirection, setSortDirection] = useState("") + const [sortField, setSortField] = useState("") + + const handleColumnClick = (column, event) => { + console.log(`click tracked on ${sortField} direction ${sortDirection}`) + setSortField(column.key) + let sortDirUpdate = (sortDirection == "" || sortDirection == DESCENDING) ? ASCENDING : DESCENDING; + console.log(sortDirUpdate) + setSortDirection(sortDirUpdate) + // Call function to sort data. + const sortedData = [...data].sort((a, b) => { + let a_value = a[column.key].toString() + let b_value = b[column.key].toString() + if(sortDirection == ASCENDING) + return a_value.localeCompare(b_value) + else + return b_value.localeCompare(a_value) + }) + + console.log(`Sorted Data by column ${column.key} \n ${JSON.stringify(data)}`) + // Update data via setTableData + setTableData(sortedData) + } + + const handleMouseEnter = (column, event) => { + console.log(`Mouse entered ${column.name}`) + } + + const handleMouseLeave = (column, event) => { + console.log(`Mouse left ${column.name}`) + } + + return ( +
+
+

Very Simple Basic Table with Row Coloring

+
+ + + + {columns.map((column) => ( + + ))} + + + + {tableData.map((entry, idx) => { + return ( + + {columns.map((column) => { + // console.log(`Making it into TR ${entry}`) + return ( + + ) + })} + + ) + })} + +
handleColumnClick(column, e)} + onMouseEnter={e => handleMouseEnter(column, e)} + onMouseLeave={e => handleMouseLeave(column, e)} + > + {getTableHeader(column, sortField, sortDirection)} +
+ {entry[column.key]} +
+
+ ) +} + +export default BasicTable \ No newline at end of file diff --git a/javascript/nextjs/tables/app/components/FixedColumnTable.tsx b/javascript/nextjs/tables/app/components/FixedColumnTable.tsx new file mode 100644 index 0000000..151219c --- /dev/null +++ b/javascript/nextjs/tables/app/components/FixedColumnTable.tsx @@ -0,0 +1,16 @@ +'use client' +import { useState } from "react"; +import { ChevronDown, ChevronUp} from "lucide-react"; + +const FixedColumnTable = ({columns, data}) => { + + return ( +
+
+

Fixed Column Table

+
+
+ ) +} + +export default FixedColumnTable \ No newline at end of file diff --git a/javascript/nextjs/tables/app/data/people.json b/javascript/nextjs/tables/app/data/people.json new file mode 100644 index 0000000..ca02110 --- /dev/null +++ b/javascript/nextjs/tables/app/data/people.json @@ -0,0 +1,50 @@ +[ + { + "name": "Michael Scott", + "position": "Regional Manager", + "episodes": 2000, + "company": "Dunder Mifflin", + "email": "michael.scott@dundermifflin.com", + "phone_number": "800-123-4567" + }, + { + "name": "Dwight Schrute", + "position": "Assitant to Regional Manager", + "company": "Dunder Mifflin", + "episodes": 1000, + "email": "dwight.schrute@dundermifflin.com", + "phone_number": "800-456-8901" + }, + { + "name": "Jim Halpert", + "position": "Salesman", + "company": "Dunder Mifflin", + "episodes": 2000, + "email": "jim.halpert@dundermifflin.com", + "phone_number": "800-456-8901" + }, + { + "name": "Pam Halpert", + "position": "Receptionist/Saleswoman", + "company": "Dunder Mifflin", + "episodes": 2000, + "email": "pam.halpert@dundermifflin.com", + "phone_number": "800-456-8902" + }, + { + "name": "Kevin Malone", + "position": "Accountant", + "company": "Dunder Mifflin", + "episodes": 2000, + "email": "kevin.malone@dundermifflin.com", + "phone_number": "800-124-5678" + }, + { + "name": "Oscar Martinez", + "position": "Accountant", + "company": "Dunder Mifflin", + "episodes": 2000, + "email": "oscar.martinez@dundermifflin.com", + "phone_number": "800-123-5678" + } +] \ No newline at end of file diff --git a/javascript/nextjs/tables/app/favicon.ico b/javascript/nextjs/tables/app/favicon.ico new file mode 100644 index 0000000..718d6fe Binary files /dev/null and b/javascript/nextjs/tables/app/favicon.ico differ diff --git a/javascript/nextjs/tables/app/globals.css b/javascript/nextjs/tables/app/globals.css new file mode 100644 index 0000000..a2dc41e --- /dev/null +++ b/javascript/nextjs/tables/app/globals.css @@ -0,0 +1,26 @@ +@import "tailwindcss"; + +:root { + --background: #ffffff; + --foreground: #171717; +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); +} + +@media (prefers-color-scheme: dark) { + :root { + --background: #0a0a0a; + --foreground: #ededed; + } +} + +body { + background: var(--background); + color: var(--foreground); + font-family: Arial, Helvetica, sans-serif; +} diff --git a/javascript/nextjs/tables/app/layout.tsx b/javascript/nextjs/tables/app/layout.tsx new file mode 100644 index 0000000..f7fa87e --- /dev/null +++ b/javascript/nextjs/tables/app/layout.tsx @@ -0,0 +1,34 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import "./globals.css"; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "Create Next App", + description: "Generated by create next app", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + {children} + + + ); +} diff --git a/javascript/nextjs/tables/app/page.tsx b/javascript/nextjs/tables/app/page.tsx new file mode 100644 index 0000000..9de0c52 --- /dev/null +++ b/javascript/nextjs/tables/app/page.tsx @@ -0,0 +1,86 @@ +import Image from "next/image"; +import BasicTable from "@/app/components/BasicTable"; +import data from "./data/people.json" +import FixedColumnTable from "@/app/components/FixedColumnTable"; + + +export default function Home() { + const columns = [ + {key: "name", name: "Name"}, + {key: "position", name: "Position"}, + {key: "episodes", name: "Episodes"}, + {key: "company", name: "Company"}, + {key: "email", name: "Email"}, + {key: "phone_number", name: "Phone Number"} + ] + + return ( +
+
+ +
+
+ +
+
+ //
+ //
+ // Next.js logo + //
+ //

+ // To get started, edit the page.tsx file. + //

+ //

+ // Looking for a starting point or more instructions? Head over to{" "} + // + // Templates + // {" "} + // or the{" "} + // + // Learning + // {" "} + // center. + //

+ //
+ //
+ // + // Vercel logomark + // Deploy Now + // + // + // Documentation + // + //
+ //
+ //
+ ); +} diff --git a/javascript/nextjs/tables/eslint.config.mjs b/javascript/nextjs/tables/eslint.config.mjs new file mode 100644 index 0000000..05e726d --- /dev/null +++ b/javascript/nextjs/tables/eslint.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig, globalIgnores } from "eslint/config"; +import nextVitals from "eslint-config-next/core-web-vitals"; +import nextTs from "eslint-config-next/typescript"; + +const eslintConfig = defineConfig([ + ...nextVitals, + ...nextTs, + // Override default ignores of eslint-config-next. + globalIgnores([ + // Default ignores of eslint-config-next: + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ]), +]); + +export default eslintConfig; diff --git a/javascript/nextjs/tables/next.config.ts b/javascript/nextjs/tables/next.config.ts new file mode 100644 index 0000000..e9ffa30 --- /dev/null +++ b/javascript/nextjs/tables/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + /* config options here */ +}; + +export default nextConfig; diff --git a/javascript/nextjs/tables/package.json b/javascript/nextjs/tables/package.json new file mode 100644 index 0000000..93651c8 --- /dev/null +++ b/javascript/nextjs/tables/package.json @@ -0,0 +1,27 @@ +{ + "name": "tables", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "eslint" + }, + "dependencies": { + "lucide-react": "^0.553.0", + "next": "16.0.1", + "react": "19.2.0", + "react-dom": "19.2.0" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.0.1", + "tailwindcss": "^4", + "typescript": "^5" + } +} diff --git a/javascript/nextjs/tables/postcss.config.mjs b/javascript/nextjs/tables/postcss.config.mjs new file mode 100644 index 0000000..61e3684 --- /dev/null +++ b/javascript/nextjs/tables/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; diff --git a/javascript/nextjs/tables/public/file.svg b/javascript/nextjs/tables/public/file.svg new file mode 100644 index 0000000..004145c --- /dev/null +++ b/javascript/nextjs/tables/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/javascript/nextjs/tables/public/globe.svg b/javascript/nextjs/tables/public/globe.svg new file mode 100644 index 0000000..567f17b --- /dev/null +++ b/javascript/nextjs/tables/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/javascript/nextjs/tables/public/next.svg b/javascript/nextjs/tables/public/next.svg new file mode 100644 index 0000000..5174b28 --- /dev/null +++ b/javascript/nextjs/tables/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/javascript/nextjs/tables/public/vercel.svg b/javascript/nextjs/tables/public/vercel.svg new file mode 100644 index 0000000..7705396 --- /dev/null +++ b/javascript/nextjs/tables/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/javascript/nextjs/tables/public/window.svg b/javascript/nextjs/tables/public/window.svg new file mode 100644 index 0000000..b2b2a44 --- /dev/null +++ b/javascript/nextjs/tables/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/javascript/nextjs/tables/tsconfig.json b/javascript/nextjs/tables/tsconfig.json new file mode 100644 index 0000000..3a13f90 --- /dev/null +++ b/javascript/nextjs/tables/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts", + "**/*.mts" + ], + "exclude": ["node_modules"] +} diff --git a/python/python-examples/test/test_haversine_distance.py b/python/python-examples/test/test_haversine_distance.py index d5f681c..5a29ceb 100644 --- a/python/python-examples/test/test_haversine_distance.py +++ b/python/python-examples/test/test_haversine_distance.py @@ -2,6 +2,7 @@ Test for haversine distance. """ import logging as log +import numpy as np from math import radians import pytest from sklearn.metrics.pairwise import haversine_distances @@ -12,6 +13,11 @@ pytest.param( [-34.83333, -58.5166646], [49.0083899664, 2.53844117956] + ), + # Google location vs USDA Location + pytest.param( + [39.0168311, -76.92883499999999], + [39.01644, -76.928925] ) ]) def test_calculate_haversince_distance(lat_long_origin:list, lat_long_destination:list): @@ -28,4 +34,43 @@ def test_calculate_haversince_distance(lat_long_origin:list, lat_long_destinatio sklearn_distance = km_distance_matrix_result[0][1] log.info(f"Raw Calc={km_haversine_distance}, Sklearn Calc={sklearn_distance}") # Rounding both to 8 digits of accuracy... - assert km_haversine_distance == round(km_distance_matrix_result[0][1], 8) \ No newline at end of file + assert km_haversine_distance == round(km_distance_matrix_result[0][1], 8) + + +def test_shortest_distance(): + # Lincoln Memorial Latlong + lincoln_memorial = [38.889248, -77.050636] + + # Ducinni's off U St + ducinnis_pizza = [38.91706701509112, -77.04118715785616] + + # Admo Jumbo Slice + jumbo_slice_pizza = [38.92105748065034, -77.04170211776945] + + # Manny Olgas Near U + manny_olgas = [38.91543818061708, -77.03174726038766] + + # Based off Haversine which is closest to Lincoln Memorial + dataset = [ + {'name': 'Lincoln Memorial', 'geocode': lincoln_memorial}, + {'name': "Ducinni's Pizza", 'geocode': ducinnis_pizza}, + {'name': 'Jumbo Slice Pizza', 'geocode': jumbo_slice_pizza}, + {'name': "Manny Olga's", 'geocode': manny_olgas} + ] + + # Put all these in radians + radian_distances = list(map(lambda x: [radians(_) for _ in x['geocode']], dataset)) + + # Calculate the Haversine Distances + distance_matrix_result = haversine_distances(radian_distances) + + # Pull out the first Entry in the 2D array + km_distance_matrix_result = distance_matrix_result * RADIUS_OF_EARTH / 1000 + log.info(f"\nDistance Matrix in Kilometers:\n {km_distance_matrix_result}") + + # Get the index of the minimum distance for the lincoln memorial + np_array = np.array(km_distance_matrix_result[0][1:]) + idx_min = np.argmin(np_array) + # Closest Should be Ducinnis + assert idx_min + 1 == 1 + log.info(f"\nClosest Jumbo Slice spot to Lincoln Memorial by Haversine Distance is {dataset[idx_min + 1]['name']}")