Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
39 changes: 27 additions & 12 deletions client/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,35 +1,50 @@
FROM node:18-alpine as base
FROM node:18-alpine AS base
RUN apk add --no-cache g++ make py3-pip libc6-compat
WORKDIR /app
COPY package*.json ./
COPY next.config.js ./

# Install dependencies including devDependencies
# This will be cached unless package.json or package-lock.json change
ENV NODE_ENV=development
RUN npm install

# Set the environment back to production for the final build
ENV NODE_ENV=production
EXPOSE 3000

FROM base as builder
FROM base AS builder
WORKDIR /app
COPY . .
RUN npm run build


FROM base as production
FROM base AS production
WORKDIR /app

# Ensure we are in production mode
ENV NODE_ENV=production
RUN npm ci
# Install only production dependencies
RUN npm ci --only=production

RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
# Setup non-root user for better security
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001
USER nextjs


# Copy necessary files from the builder stage
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/public ./public
COPY --from=builder /app/next.config.js ./next.config.js
COPY --from=builder /app/tailwind.config.ts ./tailwind.config.ts
COPY --from=builder /app/postcss.config.js ./postcss.config.js

CMD npm start
CMD ["npm", "start"]

FROM base as dev
FROM base AS dev
WORKDIR /app
ENV NODE_ENV=development
RUN npm install
# No need to run npm install again as it was done in the base stage
COPY . .
CMD npm run dev
CMD ["npm", "run", "dev"]
116 changes: 116 additions & 0 deletions client/components/charts/barchart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import React from "react";
import { Bar } from "react-chartjs-2";
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
} from "chart.js";
import { getColorForRate } from "../../utils/chartColors";

ChartJS.register(
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend
);

interface DataItem {
State: string;
Range: string;
Rate: number;
}

interface BarChartProps {
data: DataItem[];
}

const BarChart: React.FC<BarChartProps> = ({ data }) => {
// Sorting the data by state name
const sortedData = [...data].sort((a, b) => a.State.localeCompare(b.State));

// Generating background colors for each data item based on its rate
const backgroundColors = sortedData.map((item) => getColorForRate(item.Rate));

// Preparing the data structure for the chart
const chartData = {
labels: sortedData.map((item) => item.State),
datasets: [
{
label: "Cancer Incidence Rate",
data: sortedData.map((item) => item.Rate),
backgroundColor: backgroundColors,
hoverBackgroundColor: backgroundColors.map((color) => color + "CC"), // Adjust for hover state
borderColor: "rgba(75, 192, 192, 1)",
borderWidth: 1,
},
],
};

// Configuring chart options
const options = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false, // Hiding the legend as it seems unnecessary
},
tooltip: {
callbacks: {
// Customizing tooltip content
label: function (context: any) {
const index = context.dataIndex;
const state = sortedData[index].State;
const rate = sortedData[index].Rate;
const range = sortedData[index].Range;
return `State: ${state}\nRate: ${rate}\nRange: ${range}`;
},
},
},
},
interaction: {
mode: "index" as const,
intersect: false,
},
scales: {
x: {
title: {
display: true,
text: "State",
font: {
size: 14,
},
},
},
y: {
title: {
display: true,
text: "Incidence Rate",
font: {
size: 14,
},
},
beginAtZero: true,
},
},
};

// Rendering the component
return (
<div className="flex flex-col justify-center items-center h-full">
<h2 className="text-2xl font-semibold mb-4 text-gray-700 text-center">
Cancer Incidence Rates by State
</h2>
<div className="relative h-96 w-full flex-grow">
<Bar options={options} data={chartData} />
</div>
</div>
);
};

export default BarChart;
42 changes: 42 additions & 0 deletions client/components/charts/home.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from "react";
import SortableTable from "./sortabletable";
import csvData from "../../data/uscs_map_incidence_all.csv";
import PieChart from "./piechart";
import BarChart from "./barchart";

interface DataItem {
State: string;
Range: string;
Rate: number;
}

export const HomeData: React.FC = () => {
// Parse csvData and convert it to the required format for the components
const data: DataItem[] = csvData.map((item) => ({
State: item.State,
Range: item.Range,
Rate: parseFloat(item.Rate as unknown as string), // Ensure Rate is parsed as a float
}));

// Render the home page layout with a pie chart, bar chart, and sortable table
return (
<div className="container mx-auto p-8 bg-gray-50 min-h-screen">
<h1 className="text-4xl font-bold mb-8 text-center text-gray-800">
Cancer Incidence Rates by State
</h1>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-12 mb-12">
<div className="bg-white shadow rounded-lg p-8 col-span-1 lg:col-span-1">
<PieChart data={data} />
</div>
<div className="bg-white shadow rounded-lg p-8 col-span-1 lg:col-span-2">
<BarChart data={data} />
</div>
</div>
<div className="bg-white shadow rounded-lg p-8">
<SortableTable data={data} />
</div>
</div>
);
};

export default HomeData;
Loading