Guest User

Claude-implemented ambsheet prototype

a guest
Feb 4th, 2025
260
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.71 KB | None | 0 0
  1. import React, { useState, useEffect } from 'react';
  2.  
  3. const AmbSheet = () => {
  4. const initialData = [
  5. ['Budget', '', ''],
  6. ['', '', ''],
  7. ['Car', '{500,1200}', ''],
  8. ['Apartment', '{2800,3700,5500}', ''],
  9. ['Netflix', '18', ''],
  10. ['', '', ''],
  11. ['TOTAL', '', ''],
  12. ];
  13.  
  14. const initialFormulas = {
  15. 'B7': '=SUM(B3:B5)'
  16. };
  17.  
  18. const [data, setData] = useState(initialData);
  19. const [formulas, setFormulas] = useState(initialFormulas);
  20. const [selectedCell, setSelectedCell] = useState(null);
  21. const [editValue, setEditValue] = useState('');
  22.  
  23. // Parse amb values from string format {val1,val2,...}
  24. const parseAmbValue = (value) => {
  25. if (typeof value !== 'string') return null;
  26. const match = value.match(/^\{(.*)\}$/);
  27. if (!match) return null;
  28. return match[1].split(',').map(v => parseFloat(v.trim()));
  29. };
  30.  
  31. // Calculate all combinations for a range
  32. const calculateRangeCombinations = (startRow, endRow, col) => {
  33. const values = [];
  34. const ambRows = [];
  35.  
  36. // Collect all values and track which rows have amb values
  37. for (let i = startRow; i <= endRow; i++) {
  38. const value = data[i][col];
  39. const parsed = parseAmbValue(value);
  40. if (parsed) {
  41. values.push(parsed);
  42. ambRows.push(i);
  43. } else {
  44. values.push([parseFloat(value) || 0]);
  45. }
  46. }
  47.  
  48. // Generate all combinations using cartesian product
  49. const combinations = values.reduce((acc, curr) => {
  50. if (acc.length === 0) return curr.map(v => [v]);
  51. const newCombos = [];
  52. for (const combo of acc) {
  53. for (const value of curr) {
  54. newCombos.push([...combo, value]);
  55. }
  56. }
  57. return newCombos;
  58. }, []);
  59.  
  60. // Sum each combination
  61. return combinations.map(combo => combo.reduce((sum, val) => sum + val, 0));
  62. };
  63.  
  64. // Calculate value for a cell
  65. const calculateCellValue = (rowIndex, colIndex) => {
  66. const cellRef = `${String.fromCharCode(65 + colIndex)}${rowIndex + 1}`;
  67. const formula = formulas[cellRef];
  68.  
  69. if (!formula) {
  70. const value = data[rowIndex][colIndex];
  71. const parsed = parseAmbValue(value);
  72. return parsed ? `{${parsed.join(',')}}` : value;
  73. }
  74.  
  75. if (formula.toLowerCase().startsWith('=sum')) {
  76. const range = formula.match(/\((.*?)\)/)[1];
  77. const [start, end] = range.split(':');
  78.  
  79. const startCol = start.charAt(0).charCodeAt(0) - 65;
  80. const startRow = parseInt(start.slice(1)) - 1;
  81. const endRow = parseInt(end.slice(1)) - 1;
  82.  
  83. const results = calculateRangeCombinations(startRow, endRow, startCol);
  84. return `{${results.join(',')}}`;
  85. }
  86.  
  87. return formula;
  88. };
  89.  
  90. const renderCellContent = (value) => {
  91. const parsed = parseAmbValue(value);
  92. if (!parsed) return value;
  93.  
  94. return (
  95. <div className="flex flex-wrap gap-1">
  96. {parsed.map((val, idx) => (
  97. <span key={idx} className="bg-gray-100 px-2 py-1 rounded-md text-sm">
  98. {val.toLocaleString()}
  99. </span>
  100. ))}
  101. </div>
  102. );
  103. };
  104.  
  105. const handleCellClick = (rowIndex, colIndex) => {
  106. const cellRef = `${String.fromCharCode(65 + colIndex)}${rowIndex + 1}`;
  107. setSelectedCell({ row: rowIndex, col: colIndex, ref: cellRef });
  108. setEditValue(formulas[cellRef] || data[rowIndex][colIndex]);
  109. };
  110.  
  111. const handleFormulaSubmit = () => {
  112. if (!selectedCell) return;
  113.  
  114. if (editValue.startsWith('=')) {
  115. setFormulas({
  116. ...formulas,
  117. [selectedCell.ref]: editValue
  118. });
  119. } else {
  120. const newData = [...data];
  121. newData[selectedCell.row][selectedCell.col] = editValue;
  122. setData(newData);
  123. }
  124. };
  125.  
  126. return (
  127. <div className="p-8 max-w-6xl mx-auto">
  128. <div className="flex gap-8">
  129. <div className="flex-1">
  130. <h1 className="text-2xl font-bold mb-6">Ambsheet</h1>
  131.  
  132. <div className="mb-4">
  133. <div className="flex items-center space-x-2">
  134. <span className="font-medium">{selectedCell ? selectedCell.ref : ''}</span>
  135. <input
  136. type="text"
  137. value={editValue}
  138. onChange={(e) => setEditValue(e.target.value)}
  139. onKeyDown={(e) => {
  140. if (e.key === 'Enter') {
  141. handleFormulaSubmit();
  142. }
  143. }}
  144. className="flex-1 p-2 border rounded"
  145. placeholder="Enter value or formula"
  146. />
  147. </div>
  148. </div>
  149.  
  150. <div className="bg-white rounded-lg shadow-md overflow-hidden">
  151. <table className="w-full">
  152. <tbody>
  153. {data.map((row, rowIndex) => (
  154. <tr key={rowIndex} className={rowIndex === 0 ? 'bg-gray-50' : ''}>
  155. <td className="border p-2 w-8 text-gray-500 text-sm">
  156. {rowIndex + 1}
  157. </td>
  158. {row.map((cell, colIndex) => {
  159. const displayValue = calculateCellValue(rowIndex, colIndex);
  160. return (
  161. <td
  162. key={colIndex}
  163. className={`border p-2 ${
  164. selectedCell?.row === rowIndex && selectedCell?.col === colIndex
  165. ? 'bg-blue-50'
  166. : ''
  167. }`}
  168. onClick={() => handleCellClick(rowIndex, colIndex)}
  169. >
  170. {renderCellContent(displayValue)}
  171. </td>
  172. );
  173. })}
  174. </tr>
  175. ))}
  176. </tbody>
  177. </table>
  178. </div>
  179. </div>
  180.  
  181. {selectedCell && (
  182. <div className="w-96">
  183. <h2 className="text-lg font-semibold mb-4">{selectedCell.ref}</h2>
  184. <div className="bg-white rounded-lg shadow-md p-4">
  185. <div className="text-sm font-medium text-gray-500 mb-2">Value</div>
  186. <div className="mb-4">
  187. {renderCellContent(calculateCellValue(selectedCell.row, selectedCell.col))}
  188. </div>
  189.  
  190. {formulas[selectedCell.ref] && (
  191. <>
  192. <div className="text-sm font-medium text-gray-500 mb-2">Formula</div>
  193. <div className="font-mono bg-gray-50 p-2 rounded">
  194. {formulas[selectedCell.ref]}
  195. </div>
  196. </>
  197. )}
  198. </div>
  199. </div>
  200. )}
  201. </div>
  202. </div>
  203. );
  204. };
  205.  
  206. export default AmbSheet;
Advertisement
Add Comment
Please, Sign In to add comment