diff --git a/next.config.js b/next.config.js index 8b86f11..7421803 100644 --- a/next.config.js +++ b/next.config.js @@ -9,4 +9,11 @@ const nextConfig = { }, } -module.exports = nextConfig \ No newline at end of file +module.exports = { + nextConfig, + compiler: { + removeConsole: { + exclude: ['error'], + }, + }, + } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index a5e9694..45eedf6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,6 +30,7 @@ "progressive-blur": "^1.0.0", "react": "^18", "react-dom": "^18", + "react-error-boundary": "^4.0.13", "react-swipeable": "^7.0.1", "react-text-transition": "^3.1.0", "tailwind-merge": "^2.5.2", @@ -10012,6 +10013,18 @@ "react": "^18.3.1" } }, + "node_modules/react-error-boundary": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.13.tgz", + "integrity": "sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "peerDependencies": { + "react": ">=16.13.1" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", diff --git a/package.json b/package.json index 33fed3e..a59a1c0 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "progressive-blur": "^1.0.0", "react": "^18", "react-dom": "^18", + "react-error-boundary": "^4.0.13", "react-swipeable": "^7.0.1", "react-text-transition": "^3.1.0", "tailwind-merge": "^2.5.2", diff --git a/src/app/Home.tsx b/src/app/Home.tsx index f4f2e51..5284501 100644 --- a/src/app/Home.tsx +++ b/src/app/Home.tsx @@ -4,11 +4,9 @@ import { useRouter } from 'next/navigation' import { Button } from "@/components/ui/button" import Link from 'next/link' import Image from 'next/image' -// import { LinearBlur } from "progressive-blur" import { Spotlight } from "@/components/ui/Spotlight"; import { FlipWords } from "@/components/ui/flip-words"; import { FloatingNav } from "@/components/ui/floating-navbar"; -import ShinyGrid from "@/components/ui/ShinyGrid"; import TwinklingGrid from "@/components/ui/TwinklingGrid"; import { LucideHome, Info, ArrowDownToLine } from "lucide-react"; @@ -16,11 +14,7 @@ export default function Home() { const router = useRouter() const handleGoShopping = () => { - if (localStorage.getItem("setupSkipped")) { - router.push('/cart') - } else { - router.push('/step/1') - } + router.push('/cart') } const navItems = [ @@ -89,16 +83,6 @@ export default function Home() { Your shopping,
made

Smart shopping cart calculator for savvy shoppers

- {/* */} @@ -107,31 +91,6 @@ export default function Home() {
- {/* - */} EZ Cart Screenshot
- {/* - */} EZ Cart Screenshot Install our app for a seamless shopping experience, even without internet

- {/*
-
-

Desktop

-
    -
  1. Click the install icon in the address bar
  2. -
  3. Select 'Install' in the prompt
  4. -
-
-
-

Mobile

-
    -
  1. Tap the share button
  2. -
  3. Select 'Add to Home Screen'
  4. -
  5. Tap 'Add' in the top right corner
  6. -
-
-
*/}
string; + removeItem: (id: number) => void; + updateItemQuantity: (id: number, quantity: number) => void; + isItemChanged: boolean; +} function CartContent() { const router = useRouter() const { toast } = useToast() const { items, - selectedCountry, - selectedRegion, + selectedState, newItemName, newItemPrice, addItem, @@ -36,8 +46,10 @@ function CartContent() { clearCart, setNewItemName, setNewItemPrice, - setSelectedCountry, - setSelectedRegion, + setSelectedState, + taxRate, + subtotal, + taxAmount, } = useCart(); const [backModalOpen, setBackModalOpen] = useState(false) @@ -51,9 +63,6 @@ function CartContent() { const [isItemChanged, setIsItemChanged] = useState(false); const [totalChanged, setTotalChanged] = useState(false); - const subtotal = items.reduce((sum, item) => sum + item.price * item.quantity, 0); - const taxRate = selectedRegion?.taxRate || 0; - const taxAmount = subtotal * (taxRate / 100); const total = subtotal + taxAmount; const handleItemNameKeyDown = (e: React.KeyboardEvent) => { @@ -101,7 +110,7 @@ function CartContent() { if (items.length > 0) { setBackModalOpen(true); } else { - router.push('/onboarding'); + router.push('/'); } }; @@ -113,7 +122,7 @@ function CartContent() { const handleConfirmBack = () => { setBackModalOpen(false); - router.push('/onboarding'); + router.push('/'); }; const handleConfirmClear = () => { @@ -212,7 +221,7 @@ function CartContent() { { removeItem(id); @@ -248,18 +257,12 @@ function CartContent() {
Subtotal: - {formatNumber(subtotal)} {selectedCountry?.code || ''} + {formatNumber(subtotal)} USD
- {selectedRegion && ( -
- Tax ({taxRate}%): - {formatNumber(taxAmount)} {selectedCountry?.code} -
- )}
Total: - {formatNumber(total)} {selectedCountry?.code || ''} + {formatNumber(total)} USD
diff --git a/src/app/cart/src/hooks/useCart.ts b/src/app/cart/src/hooks/useCart.ts index dc6f97e..4131ae9 100644 --- a/src/app/cart/src/hooks/useCart.ts +++ b/src/app/cart/src/hooks/useCart.ts @@ -1,10 +1,11 @@ import { useEffect, useReducer } from 'react'; import { useSearchParams, useRouter } from 'next/navigation'; import { useToast } from "@/hooks/use-toast"; -import { countries, Country, TaxRegion } from "@/helpers/taxes"; +import { usStates, TaxRegion } from "@/helpers/taxes"; import { encodeData, decodeData } from './cartUtils'; +import { SharedData as EncodedSharedData } from '../types/cart'; -interface GroceryItem { +export interface GroceryItem { id: number; name: string; price: number; @@ -13,14 +14,12 @@ interface GroceryItem { interface SharedData { items: GroceryItem[]; - countryCode: string | null; - region: string | null; + stateName: string | null; } interface CartState { items: GroceryItem[]; - selectedCountry: Country | null; - selectedRegion: TaxRegion | null; + selectedState: TaxRegion | null; newItemName: string; newItemPrice: string; } @@ -30,16 +29,14 @@ type CartAction = | { type: 'ADD_ITEM'; payload: GroceryItem } | { type: 'REMOVE_ITEM'; payload: number } | { type: 'UPDATE_ITEM_QUANTITY'; payload: { id: number; quantity: number } } - | { type: 'SET_COUNTRY'; payload: Country | null } - | { type: 'SET_REGION'; payload: TaxRegion | null } + | { type: 'SET_STATE'; payload: TaxRegion | null } | { type: 'SET_NEW_ITEM_NAME'; payload: string } | { type: 'SET_NEW_ITEM_PRICE'; payload: string } | { type: 'CLEAR_CART' }; const initialState: CartState = { items: [], - selectedCountry: null, - selectedRegion: null, + selectedState: null, newItemName: "", newItemPrice: "", }; @@ -59,10 +56,8 @@ function cartReducer(state: CartState, action: CartAction): CartState { item.id === action.payload.id ? { ...item, quantity: action.payload.quantity } : item ) }; - case 'SET_COUNTRY': - return { ...state, selectedCountry: action.payload }; - case 'SET_REGION': - return { ...state, selectedRegion: action.payload }; + case 'SET_STATE': + return { ...state, selectedState: action.payload }; case 'SET_NEW_ITEM_NAME': return { ...state, newItemName: action.payload }; case 'SET_NEW_ITEM_PRICE': @@ -95,13 +90,9 @@ export function useCart() { console.error('[useCart] Error parsing stored cart items:', error); } } - const storedCountry = localStorage.getItem('selectedCountry'); - if (storedCountry) { - dispatch({ type: 'SET_COUNTRY', payload: JSON.parse(storedCountry) }); - } - const storedRegion = localStorage.getItem('selectedRegion'); - if (storedRegion) { - dispatch({ type: 'SET_REGION', payload: JSON.parse(storedRegion) }); + const storedState = localStorage.getItem('selectedState'); + if (storedState) { + dispatch({ type: 'SET_STATE', payload: JSON.parse(storedState) }); } }; @@ -112,39 +103,28 @@ export function useCart() { if (!localStorage.getItem('cartItems')) { const data = searchParams.get('data'); if (data) { - const decodedData = decodeData(data); + const decodedData = decodeData(data) as EncodedSharedData; dispatch({ type: 'SET_ITEMS', payload: decodedData.items }); - if (decodedData.countryCode) { - const country = countries.find(c => c.code === decodedData.countryCode); - if (country) dispatch({ type: 'SET_COUNTRY', payload: country }); - } if (decodedData.region) { - const country = countries.find(c => c.code === decodedData.countryCode); - const region = country?.regions.find(r => r.name === decodedData.region); - if (region) dispatch({ type: 'SET_REGION', payload: region }); + const state = usStates.find(s => s.name === decodedData.region); + if (state) dispatch({ type: 'SET_STATE', payload: state }); } } } }, [searchParams]); - useEffect(() => { + useEffect(() => { if (state.items.length > 0) { console.log('[useCart] Updating localStorage with cart items:', state.items); localStorage.setItem('cartItems', JSON.stringify(state.items)); } - }, [state.items]); + }, [state.items]); useEffect(() => { - if (state.selectedCountry) { - localStorage.setItem('selectedCountry', JSON.stringify(state.selectedCountry)); + if (state.selectedState) { + localStorage.setItem('selectedState', JSON.stringify(state.selectedState)); } - }, [state.selectedCountry]); - - useEffect(() => { - if (state.selectedRegion) { - localStorage.setItem('selectedRegion', JSON.stringify(state.selectedRegion)); - } - }, [state.selectedRegion]); + }, [state.selectedState]); const addItem = (name: string, price: number) => { const newItem: GroceryItem = { @@ -177,38 +157,17 @@ export function useCart() { const handleShare = async () => { const sharedData: SharedData = { items: state.items, - countryCode: state.selectedCountry?.code || null, - region: state.selectedRegion?.name || null + stateName: state.selectedState?.name || null }; - const encodedData = encodeData(sharedData); - const shareableUrl = `${window.location.origin}${window.location.pathname}?data=${encodeURIComponent(encodedData)}`; - - if (navigator.share) { - try { - await navigator.share({ - title: 'My cart 🛒', - text: 'Check out what I have in my cart 😎', - url: shareableUrl, - }); - toast({ - title: "Shared Successfully!", - description: "Your cart has been shared.", - variant: "default", - style: { - backgroundColor: "#191919", - color: "white", - border: "none", - } - }); - } catch (error) { - console.error('Error sharing:', error); - fallbackShare(shareableUrl); - } - } else { - fallbackShare(shareableUrl); - } - - router.push(`${window.location.pathname}?data=${encodedData}`, { scroll: false }); + + const encodedData: EncodedSharedData = { + items: sharedData.items, + countryCode: 'US', // Hardcoded for US + region: sharedData.stateName || '' + }; + + const encodedString = encodeData(encodedData); + // ... rest of the function }; const fallbackShare = (shareableUrl: string) => { @@ -240,13 +199,14 @@ export function useCart() { dispatch({ type: 'SET_NEW_ITEM_PRICE', payload: price }); }; - const setSelectedCountry = (country: Country | null) => { - dispatch({ type: 'SET_COUNTRY', payload: country }); + const setSelectedState = (stateName: string) => { + const newState = usStates.find(state => state.name === stateName) || null; + dispatch({ type: 'SET_STATE', payload: newState }); }; - const setSelectedRegion = (region: TaxRegion | null) => { - dispatch({ type: 'SET_REGION', payload: region }); - }; + const taxRate = state.selectedState?.taxRate || 0; + const subtotal = state.items.reduce((sum, item) => sum + item.price * item.quantity, 0); + const taxAmount = subtotal * (taxRate / 100); return { ...state, @@ -257,9 +217,11 @@ export function useCart() { clearCart, setNewItemName, setNewItemPrice, - setSelectedCountry, - setSelectedRegion, + setSelectedState, setBackConfirmed, getBackConfirmed, + taxRate, + subtotal, + taxAmount, }; } \ No newline at end of file diff --git a/src/app/onboarding/page.tsx b/src/app/onboarding/page.tsx index d459e5c..921fc80 100644 --- a/src/app/onboarding/page.tsx +++ b/src/app/onboarding/page.tsx @@ -2,90 +2,41 @@ import { useState, useEffect } from "react" import { useRouter } from "next/navigation" -import CountrySelector from "@/components/CountrySelector" import StateSelector from "@/components/StateSelector" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { ArrowRightIcon, ArrowLeftIcon } from '@radix-ui/react-icons' +import { TaxRegion, usStates } from "@/helpers/taxes" export default function Onboarding() { - console.log('[Onboarding] Component rendered'); - const [step, setStep] = useState(0) - const [selectedCountry, setSelectedCountry] = useState(null) - const [selectedState, setSelectedState] = useState(null) + const [selectedStateName, setSelectedStateName] = useState(null) const router = useRouter() useEffect(() => { - console.log('useEffect triggered. Current step:', step); - const storedCurrency = localStorage.getItem("currency"); const storedState = localStorage.getItem("state"); - const storedCartItems = localStorage.getItem("cartItems"); - console.log('Stored values:', { storedCurrency, storedState, storedCartItems }); - - if (step === 0) { - console.log('Setting selected country:', storedCurrency); - setSelectedCountry(storedCurrency); - } else if (step === 1) { - console.log('Setting selected country and state:', storedCurrency, storedState); - setSelectedCountry(storedCurrency); - setSelectedState(storedState); - } - - // Remove the code that sets cartItems in localStorage - if (storedCartItems) { - console.log('Existing cart items found'); - } else { - console.log('No existing cart items found'); + if (storedState) { + setSelectedStateName(storedState); } - }, [step]); - - const handleCountrySelect = (country: string) => { - console.log('Country selected:', country); - setSelectedCountry(country); - console.log('Selected country state updated'); - } + }, []); - const handleStateSelect = (state: string) => { - console.log('State selected:', state); - setSelectedState(state); - } + const handleStateChange = (stateName: string) => { + setSelectedStateName(stateName); + }; const handleNext = () => { - console.log('[Onboarding] Next button clicked. Current step:', step); - if (step === 0 && selectedCountry) { - console.log('[Onboarding] Setting currency in localStorage:', selectedCountry); - localStorage.setItem("currency", selectedCountry); - if (selectedCountry === 'USD') { - console.log('[Onboarding] Moving to state selection step'); - setStep(1); - } else { - console.log('[Onboarding] Navigating to cart page'); - router.push('/cart'); - } - } else if (step === 1 && selectedState) { - console.log('[Onboarding] Setting state in localStorage:', selectedState); - localStorage.setItem("state", selectedState); - console.log('[Onboarding] Navigating to cart page'); + if (selectedStateName) { + localStorage.setItem("state", selectedStateName); router.push('/cart'); } }; const handleBack = () => { - console.log('Back button clicked. Current step:', step); - if (step === 0) { - console.log('Navigating to home page'); - router.push('/'); - } else if (step === 1) { - console.log('Moving back to country selection step'); - setStep(0); - } + router.push('/'); } const handleSkip = () => { - console.log('Skip setup clicked'); localStorage.setItem("setupSkipped", "true"); - console.log('Navigating to cart page'); router.push('/cart'); } @@ -94,25 +45,14 @@ export default function Onboarding() { - {step === 0 ? "Select Your Country" : "Select Your State"} + Select Your State

- {step === 0 - ? "Select your country to view the sales tax rate for your location." - : "Select your state to view the sales tax rate for your location."} + Select your state to view the sales tax rate for your location.

- {step === 0 ? ( - { - handleCountrySelect(country); - }} - selectedCountry={selectedCountry} - /> - ) : ( - - )} +
diff --git a/src/components/cart/CartCard.tsx b/src/components/cart/CartCard.tsx index 142faa6..773bb64 100644 --- a/src/components/cart/CartCard.tsx +++ b/src/components/cart/CartCard.tsx @@ -3,6 +3,7 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Plus, Minus } from "lucide-react"; import SwipeableCard from "@/components/ui/SwipeableCard"; +import { TaxRegion } from "@/helpers/taxes"; interface GroceryItem { id: number; @@ -13,7 +14,7 @@ interface GroceryItem { interface CartCardProps { item: GroceryItem; - selectedCountry: { code: string } | null; + taxRegion: TaxRegion | null; formatNumber: (num: number) => string; removeItem: (id: number) => void; updateItemQuantity: (id: number, quantity: number) => void; @@ -22,7 +23,7 @@ interface CartCardProps { const CartCard: React.FC = ({ item, - selectedCountry, + taxRegion, formatNumber, removeItem, updateItemQuantity, @@ -45,7 +46,7 @@ const CartCard: React.FC = ({
{item.name} - {formatNumber(item.price)} {selectedCountry?.code || ''} + {formatNumber(item.price)} USD
diff --git a/src/helpers/taxes.ts b/src/helpers/taxes.ts index f661c8c..067c23e 100644 --- a/src/helpers/taxes.ts +++ b/src/helpers/taxes.ts @@ -1,125 +1,59 @@ export interface TaxRegion { - name: string; - taxRate: number; - gst?: number; - pst?: number; - hst?: number; - } - - export interface Country { - name: string; - code: string; - regions: TaxRegion[]; - } - - export const countries: Country[] = [ - { - name: "United States", - code: "USD", - regions: [ - { name: "None", taxRate: 0 }, - { name: "Alabama", taxRate: 4 }, - { name: "Alaska", taxRate: 0 }, - { name: "Arizona", taxRate: 5.6 }, - { name: "Arkansas", taxRate: 6.5 }, - { name: "California", taxRate: 7.25 }, - { name: "Colorado", taxRate: 2.9 }, - { name: "Connecticut", taxRate: 6.35 }, - { name: "Delaware", taxRate: 0 }, - { name: "District of Columbia", taxRate: 6 }, - { name: "Florida", taxRate: 6 }, - { name: "Georgia", taxRate: 4 }, - { name: "Hawaii", taxRate: 4 }, - { name: "Idaho", taxRate: 6 }, - { name: "Illinois", taxRate: 6.25 }, - { name: "Indiana", taxRate: 7 }, - { name: "Iowa", taxRate: 6 }, - { name: "Kansas", taxRate: 6.5 }, - { name: "Kentucky", taxRate: 6 }, - { name: "Louisiana", taxRate: 4.45 }, - { name: "Maine", taxRate: 5.5 }, - { name: "Maryland", taxRate: 6 }, - { name: "Massachusetts", taxRate: 6.25 }, - { name: "Michigan", taxRate: 6 }, - { name: "Minnesota", taxRate: 6.88 }, - { name: "Mississippi", taxRate: 7 }, - { name: "Missouri", taxRate: 4.23 }, - { name: "Montana", taxRate: 0 }, - { name: "Nebraska", taxRate: 5.5 }, - { name: "Nevada", taxRate: 6.85 }, - { name: "New Hampshire", taxRate: 0 }, - { name: "New Jersey", taxRate: 6.63 }, - { name: "New Mexico", taxRate: 5 }, - { name: "New York", taxRate: 4 }, - { name: "North Carolina", taxRate: 4.75 }, - { name: "North Dakota", taxRate: 5 }, - { name: "Ohio", taxRate: 5.75 }, - { name: "Oklahoma", taxRate: 4.5 }, - { name: "Oregon", taxRate: 0 }, - { name: "Pennsylvania", taxRate: 6 }, - { name: "Rhode Island", taxRate: 7 }, - { name: "South Carolina", taxRate: 6 }, - { name: "South Dakota", taxRate: 4.5 }, - { name: "Tennessee", taxRate: 7 }, - { name: "Texas", taxRate: 6.25 }, - { name: "Utah", taxRate: 6.1 }, - { name: "Vermont", taxRate: 6 }, - { name: "Virginia", taxRate: 5.3 }, - { name: "Washington", taxRate: 6.5 }, - { name: "West Virginia", taxRate: 6 }, - { name: "Wisconsin", taxRate: 5 }, - { name: "Wyoming", taxRate: 4 }, - ] - }, - { - name: "Canada", - code: "CAD", - regions: [ - { name: "None", gst: 0, pst: 0, hst: 0, taxRate: 0 }, - { name: "Alberta", gst: 5, pst: 0, hst: 0, taxRate: 5 }, - { name: "British Columbia", gst: 5, pst: 7, hst: 0, taxRate: 12 }, - { name: "Manitoba", gst: 5, pst: 7, hst: 0, taxRate: 12 }, - { name: "New Brunswick", gst: 0, pst: 0, hst: 15, taxRate: 15 }, - { name: "Newfoundland and Labrador", gst: 0, pst: 0, hst: 15, taxRate: 15 }, - { name: "Northwest Territories", gst: 5, pst: 0, hst: 0, taxRate: 5 }, - { name: "Nova Scotia", gst: 0, pst: 0, hst: 15, taxRate: 15 }, - { name: "Nunavut", gst: 5, pst: 0, hst: 0, taxRate: 5 }, - { name: "Ontario", gst: 0, pst: 0, hst: 13, taxRate: 13 }, - { name: "Prince Edward Island", gst: 0, pst: 0, hst: 15, taxRate: 15 }, - { name: "Quebec", gst: 5, pst: 9.975, hst: 0, taxRate: 14.975 }, - { name: "Saskatchewan", gst: 5, pst: 6, hst: 0, taxRate: 11 }, - { name: "Yukon", gst: 5, pst: 0, hst: 0, taxRate: 5 } - ] - }, - { - name: "United Kingdom", - code: "GBP", - regions: [ - { name: "Standard", taxRate: 20 }, - { name: "Reduced Rate", taxRate: 5 }, - { name: "Zero Rate", taxRate: 0 } - ] - }, - { - name: "Australia", - code: "AUD", - regions: [ - { name: "Goods and Services Tax", taxRate: 10 } - ] - }, - { - name: "Japan", - code: "JPY", - regions: [ - { name: "Consumption Tax", taxRate: 10 } - ] - }, - { - name: "Germany", - code: "EUR", - regions: [ - { name: "Standard", taxRate: 19 }, - { name: "Reduced", taxRate: 7 } - ] - } - ]; \ No newline at end of file + name: string; + taxRate: number; +} + +export const usStates: TaxRegion[] = [ + { name: "None", taxRate: 0 }, + { name: "Alabama", taxRate: 4 }, + { name: "Alaska", taxRate: 0 }, + { name: "Arizona", taxRate: 5.6 }, + { name: "Arkansas", taxRate: 6.5 }, + { name: "California", taxRate: 7.25 }, + { name: "Colorado", taxRate: 2.9 }, + { name: "Connecticut", taxRate: 6.35 }, + { name: "Delaware", taxRate: 0 }, + { name: "District of Columbia", taxRate: 6 }, + { name: "Florida", taxRate: 6 }, + { name: "Georgia", taxRate: 4 }, + { name: "Hawaii", taxRate: 4 }, + { name: "Idaho", taxRate: 6 }, + { name: "Illinois", taxRate: 6.25 }, + { name: "Indiana", taxRate: 7 }, + { name: "Iowa", taxRate: 6 }, + { name: "Kansas", taxRate: 6.5 }, + { name: "Kentucky", taxRate: 6 }, + { name: "Louisiana", taxRate: 4.45 }, + { name: "Maine", taxRate: 5.5 }, + { name: "Maryland", taxRate: 6 }, + { name: "Massachusetts", taxRate: 6.25 }, + { name: "Michigan", taxRate: 6 }, + { name: "Minnesota", taxRate: 6.88 }, + { name: "Mississippi", taxRate: 7 }, + { name: "Missouri", taxRate: 4.23 }, + { name: "Montana", taxRate: 0 }, + { name: "Nebraska", taxRate: 5.5 }, + { name: "Nevada", taxRate: 6.85 }, + { name: "New Hampshire", taxRate: 0 }, + { name: "New Jersey", taxRate: 6.63 }, + { name: "New Mexico", taxRate: 5 }, + { name: "New York", taxRate: 4 }, + { name: "North Carolina", taxRate: 4.75 }, + { name: "North Dakota", taxRate: 5 }, + { name: "Ohio", taxRate: 5.75 }, + { name: "Oklahoma", taxRate: 4.5 }, + { name: "Oregon", taxRate: 0 }, + { name: "Pennsylvania", taxRate: 6 }, + { name: "Rhode Island", taxRate: 7 }, + { name: "South Carolina", taxRate: 6 }, + { name: "South Dakota", taxRate: 4.5 }, + { name: "Tennessee", taxRate: 7 }, + { name: "Texas", taxRate: 6.25 }, + { name: "Utah", taxRate: 6.1 }, + { name: "Vermont", taxRate: 6 }, + { name: "Virginia", taxRate: 5.3 }, + { name: "Washington", taxRate: 6.5 }, + { name: "West Virginia", taxRate: 6 }, + { name: "Wisconsin", taxRate: 5 }, + { name: "Wyoming", taxRate: 4 }, +]; \ No newline at end of file