numbering scheme for a hierarchical structure, where each item has a “level” indicating its depth in the hierarchy

The numbering follows these rules:

  1. If an item is at level 1, its number is simply its position at level 1.

  2. If an item is at a higher level than the previous item, it becomes a child of the previous item, and its number is an extension of the previous item’s number with an additional segment.

  3. If an item is at the same level as the previous item, it is considered a sibling of the previous item. Its number is formed by incrementing the last segment of the previous item’s number.

  4. If an item is at a lower level than the previous item, it becomes a child of the nearest ancestor at the same level. Its number is formed by resetting the numbering at its level and incrementing it.

These rules apply as you traverse through the list of items. The numbering system allows for a clear representation of the hierarchical relationships between items in the structure.

if input json is

const jsonData1 = [
  { "name": 'Fruit', "level": 1 },
  { "name": 'Apple', "level": 2 },
  { "name": 'Banana', "level": 3 },
  { "name": 'Fruit loops', "level": 2 },
  { "name": 'Vegetables', "level": 3 },
  { "name": 'Green', "level": 4 },
  { "name": 'Green', "level": 4 },
  { "name": 'Green', "level": 5 },
  { "name": 'Orange', "level": 1 },
  { "name": 'Broccoli', "level": 1 },
  { "name": 'Brussels sprouts', "level": 2 },
  { "name": 'Pumpkins', "level": 2 },
  { "name": 'Carrots', "level": 3 }
];

output is to generate globally followed hierarchy using levels

[
  { name: 'Fruit', level: 1, number: '1' },
  { name: 'Apple', level: 2, number: '1.1' },
  { name: 'Banana', level: 3, number: '1.1.1' },
  { name: 'Fruit loops', level: 2, number: '1.2' },
  { name: 'Vegetables', level: 3, number: '1.2.1' },
  { name: 'Green', level: 4, number: '1.2.1.1' },
  { name: 'Green', level: 4, number: '1.2.1.2' },
  { name: 'Green', level: 5, number: '1.2.1.2.1' },
  { name: 'Orange', level: 1, number: '2' },
  { name: 'Broccoli', level: 1, number: '3' },
  { name: 'Brussels sprouts', level: 2, number: '3.1' },
  { name: 'Pumpkins', level: 2, number: '3.2' },
  { name: 'Carrots', level: 3, number: '3.2.1' }
]

i am getting output

"[{'name':'Fruit','level':1,'number':'1'},{'name':'Apple','level':2,'number':'1.1'},{'name':'Banana','level':3,'number':'1.1.1'},{'name':'Fruit loops','level':2,'number':'1.2'},{'name':'Vegetables','level':3,'number':'1.2.2'},{'name':'Green','level':4,'number':'1.2.2.1'},{'name':'Green','level':4,'number':'1.2.2.2'},{'name':'Green','level':5,'number':'1.2.2.2.1'},{'name':'Orange','level':1,'number':'2'},{'name':'Broccoli','level':1,'number':'3'},{'name':'Brussels sprouts','level':2,'number':'3.3'},{'name':'Pumpkins','level':2,'number':'3.4'},{'name':'Carrots','level':3,'number':'3.4.3'}]"

can someone explain where my logic fails and explain the same.
thanks for your response.

my code is

function generateHierarchicalNumbering(data) {
  const numbering = [];
  const levelCount = {};

  for (const item of data) {
    const currentLevel = item.level;

    if (!(currentLevel in levelCount)) {
      levelCount[currentLevel] = 1;
    } else {
      levelCount[currentLevel]++;
    }

    let currentNumber = '';
    for (let i = 1; i <= currentLevel; i++) {
      if (i > 1) currentNumber += '.';
      currentNumber += levelCount[i] || '1';
    }

    item.number = currentNumber;
    numbering.push({ ...item });
  }

  return numbering;
}

// Test cases
const jsonData1 = [
  { "name": 'Fruit', "level": 1 },
  { "name": 'Apple', "level": 2 },
  { "name": 'Banana', "level": 3 },
  { "name": 'Fruit loops', "level": 2 },
  { "name": 'Vegetables', "level": 3 },
  { "name": 'Green', "level": 4 },
  { "name": 'Green', "level": 4 },
  { "name": 'Green', "level": 5 },
  { "name": 'Orange', "level": 1 },
  { "name": 'Broccoli', "level": 1 },
  { "name": 'Brussels sprouts', "level": 2 },
  { "name": 'Pumpkins', "level": 2 },
  { "name": 'Carrots', "level": 3 }
];

console.log(JSON.stringify(generateHierarchicalNumbering(jsonData1)));

Scroll animation where sections fade in on top of each other

On a website with multiple sections (each have 100vw and at least 100vh) I would like to achieve an effect where whenever the user scrolls, instead of “moving” the dom upwards revealing further sections like a normal webpage would work, the following section would fade in on top of the previous. (exact opposite effect when scrolling upwards) I made a simple animation to illustrate the effect:

Animation

Now, since the sections would fade in on top of each other, they would all have to be absolutely positioned on the top of the page. That way, I could make only the current section visible and the rest hidden, changing the visibility as the user scrolls. This has some caveats though:

  • How would the user trigger a scroll event if all the sections are positioned on top and they might not be larger than the viewport height?
  • How would the scrollbar remain in its proper position based on the current section if again, everything is on the top?
  • How would I show a regular layout without the fadein animations and absolutely postioned elements if the user had no javascript enabled.

The only sollution to all those problems I could come up with is to create identical copies of all the sections so that the copies could have a fixed position on top with the fadein animation. That way, the copies could be all invisible by default in case user has no javascript and the user would always be able to trigger scroll events, since there would always be the regular layout underneath and the fixed copies would be just an overlay. (this would also fix the scrollbar position issue). This isn’t great however, since it creates some obvious performance issues and hinders DX quite significantly.

So, is there any way to achieve this particular effect without messy sollutions? Maybe there’s a name for it so that I could look up how others did it because I feel like I’ve seen it before – just can’t remember where.

I can’t understand what is wrong with my code still shows error after fixing a lot

import React, { Component } from 'react';
import ParticlesBg from 'particles-bg';
import FaceRecognition from './components/FaceRecognition/FaceRecognition';
import Navigation from './components/Navigation/Navigation';
import Register from './components/Register/Register';
import Logo from './components/Logo/Logo';
import ImageLinkForm from './components/ImageLinkForm/ImageLinkForm';
import Rank from './components/Rank/Rank';
import './App.css';

const MODEL_ID = 'face-detection';
const MODEL_VERSION_ID = 'aa7f35c01e0642fda5cf400f543e7c40';

const returnsetupClarifaiRequestOptions = (imageUrl) => {
  const PAT = '63d0f192c413485fb87bdac9dbbf6b57';
  const USER_ID = '2c8khwr2d72y';
  const APP_ID = 'Test';
  const IMAGE_URL = 'https://samples.clarifai.com/metro-north.jpg';

  const raw = JSON.stringify({
    "user_app_id": {
      "user_id": USER_ID,
      "app_id": APP_ID
    },
    "inputs": [
      {
        "data": {
          "image": {
            "url": IMAGE_URL
          }
        }
      }
    ]
  });

  const requestOptions = {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Authorization': 'Key ' + PAT
    },
    body: raw
  };

  return requestOptions;
}

class App extends Component {
  constructor() {
    super();
    this.state = {
      input: '',
      imageUrl: '',
      box: {},
      route: 'register', // Set the default route to 'register'
      isSignedIn: false,
      user: {
        id: '',
        name: '',
        email: '',
        entries: 0,
        joined: ''
      }
    };
  }

  loadUser = (data) => {
    this.setState({
      user: {
        id: data.id,
        name: data.name,
        email: data.email,
        entries: data.entries,
        joined: data.joined
      }
    })
  }

  calculateFaceLocation = (data) => {
    try {
      const clarifaiFace = data.outputs[0].data.regions[0].region_info.bounding_box;
      if (!clarifaiFace) {
        throw new Error("Bounding box information not found in Clarifai response.");
      }

      const image = document.getElementById('inputimage');
      const width = Number(image.width);
      const height = Number(image.height);

      return {
        leftCol: clarifaiFace.left_col * width,
        topRow: clarifaiFace.top_row * height,
        rightCol: width - (clarifaiFace.right_col * width),
        bottomRow: height - (clarifaiFace.bottom_row * height)
      };
    } catch (error) {
      console.error("Error calculating face location:", error.message);
      return {}; // Return an empty object or handle the error as needed
    }
  }

  displayFaceBox = (box) => {
    this.setState({ box: box });
  }

  onInputChange = (event) => {
    this.setState({ input: event.target.value });
  }

  onButtonSubmit = () => {
    this.setState({ imageUrl: this.state.input });

    fetch("https://api.clarifai.com/v2/models/" + MODEL_ID + "/versions/" + MODEL_VERSION_ID + "/outputs", returnsetupClarifaiRequestOptions(this.state.input))
      .then(response => response.json())
      .then(response => {
        console.log('hi', response)
        if (response) {
          fetch('http://localhost:3000/image', {
            method: 'put',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
              id: this.state.user.id
            })
          })
            .then(response => response.json())
            .then(count => {
              this.setState(Object.assign(this.state.user, { entries: count }))
            })
        }
        this.displayFaceBox(this.calculateFaceLocation(response))
      })
      .catch(err => console.log(err));
  }

  onRouteChange = (route) => {
    this.setState({ route: route });
  }

  render() {
    const { imageUrl, route, box } = this.state;
    return (
      <div className="App">
        <ParticlesBg type="fountain" bg={true} />
        <Navigation onRouteChange={this.onRouteChange} />
        {route === 'register' ? (
          <div>
            <Logo />
            <Rank
              name={this.state.user.name}
              entries={this.state.user.entries}
            />
            <ImageLinkForm
              onInputChange={this.onInputChange}
              onButtonSubmit={this.onButtonSubmit}
            />
            <FaceRecognition box={box} imageUrl={imageUrl} />
          </div>
        ) : (
          <Register loadUser={this.loadUser} onRouteChange={this.onRouteChange} />
        )}
      </div>
    );
  }
}

export default App;

I have used Clarifai face detection api for my face detection project.

App.js:113 
        
        
       POST https://api.clarifai.com/v2/models/face-detection/versions/aa7f35c01e0642fda5cf400f543e7c40/outputs 404 (Not Found)
Error calculating face location: Cannot read properties of undefined (reading 'data')

App.js:118 
 PUT http://localhost:3000/image 404 (Not Found)




 request to the Clarifai API and the other involving a PUT request to a local endpoint.
detection/versions/aa7f35c01e0642fda5cf400f543e7c40/outputs 404 (Not Found):
This error suggests that the endpoint you are trying to access on the Clarifai API is not found. A 
This error seems to be related to the response from the Clarifai API
This error suggests that there is an issue with the PUT request to the local endpoint at http://localhost:3000/image. The server is responding with a 404 error, indicating that the specified route or resource is not found.

Extend promise while resolving

I tried to extend a promise while its resolution is ongoing.

(async () => {
  var p4 = Promise.resolve([3]);
  var rec = (s) => {
    let x = s.pop();
    s.push(x - 1);
    if (x > 0) {
      console.log(x);
      p4.then(rec);
    }
  };
  p4.then(rec);
  console.log("result", (await p4)[0]);
})();

My problem is: the recursion works as expected (3, 2, 1 is printed), but the result is 2 instead of 0. It seems to me that the last line just sees the first step of the recursion. It follows only those continuations, which have been added till the resolution starts. Those which are added while the resolution is ongoing are ignored. How to fix this?

Conditional Site-loading in React

In my React-Web-App I am facing the problem that the conditional loading isn’t working like I want it to. I want the Login page to be the first page a user sees. If the user doesn’t have an account, there is a register Button. However, I made a condition that if a user is not logged in, only the Login page should be displayed (so only this page should be visible and other pages like “home” are not accessible.) Here is the code for the condition:

const renderAuthButton = () => {
    if (auth.authState) {
      // User is logged in, display logout button
      return (
      <div>
      <Link to="/" className="homeCSS">Home Page</Link>
      <Link to="/logout" className="logoutCSS">Logout</Link>
      </div>
      )
    } else { 
      // User is not logged in, display login button
      return <Navigate to="/login"/>
    }
  };

  return (
    <>
      {renderAuthButton()}
    </>
  );
}

Now, the register page is also not accessible because of that condition and I cannot find a way to make it work. Here is the function App if it provides any help:

function App() {
const auth = useAuth();
  return (
      <Router>
          <AuthProvider>
          <aside className="aside1"></aside>
          <header className="header">
            <Navigation />
          </header>
          <main className="main">
          <Routes>
          <Route path="/" exact element={<Home />} />
            <Route path="/thread/:id" exact element={<Thread />} />
            <Route path="/createthread" exact element={<CreateThread/>} />
            <Route path="/login" element={<Login />} />
            <Route path="/register" element={<Registration />} />
            <Route path="/logout" element={<Logout />} />
          </Routes>
          </main>
          <aside className="aside2"> 
            <NavigationCreateThread/>
          </aside>
          <footer className="footer"></footer>
          </AuthProvider>
      </Router>
  );
}
export default App;

Anyone can provide any help?

some questions about fragment interpolation when i draw a dash line with WebGL

I want draw dashed lines with webgl. And my vertex shader and fragment shader as flows.

======= vertex sahder ======

/** vetex shader */
export const vert = `
precision mediump float;

/** 当前点 */
attribute vec2 position;
varying vec2 vPosition;
/** 上一个点 */
attribute vec2 prePosition;
/** 下一个点 */
attribute vec2 nextPosition;
/** TODO: 斜接方向向量 1或者-1 */
attribute float aCorner;
/** 当前点距离 */
attribute float aDistance;
varying highp float vDistance;

/** 当前线段的向量(方向)*/
varying vec2 vDirection;
varying float vCanvasHeight;

/** 法向量(shader中计算) */
// attribute float miter;

/** 屏幕尺寸 */
uniform vec2 u_Resolution;
/** 线宽px */
uniform float width;

void main() {

  vDistance = aDistance;
  vPosition = position;
  vCanvasHeight = u_Resolution.y;

  vec2 pre = prePosition;
  vec2 next = nextPosition;

  if (all(equal(position, pre))) {
    pre = position + position - next;
  }

  if (all(equal(position.xy, next.xy))) {
    next = position + position - pre;
  }

  /** 线段方向 */
  vec2 AB = normalize(position - pre);
  // vDirection = AB;
  
  vec2 BC = normalize(next - position);
  vDirection = BC;

  /** 计算切线 */
  vec2 tangent = normalize(AB + BC);

  /** 计算斜接方向 */
  vec2 miter = vec2(-tangent.y, tangent.x);

  vec2 normalA = vec2(-AB.y, AB.x);
  float d = width / dot(miter, normalA);

  vec2 glPosition = position + (miter * aCorner * d);

  vec2 zeroToOne = glPosition / u_Resolution;
  vec2 zeroToTwo = zeroToOne * 2.0;
  vec2 clipSpace = zeroToTwo - 1.0;
  clipSpace = clipSpace * vec2(1.0, -1.0);
  gl_Position = vec4(clipSpace, 0, 1);

}`;

======= fragment shader ======

/** 片元着色器 */
export const frag = `
precision mediump float;
uniform vec4 u_Color;

varying highp float vDistance;
varying vec2 vPosition;
varying vec2 vDirection;
varying float vCanvasHeight;

void main() {
  // /** 将屏幕坐标系坐标转为canvas坐标系坐标 */
  // vec2 canvasPos = vec2(gl_FragCoord.x, vCanvasHeight - gl_FragCoord.y);

  // /** 计算当前 fragment 距离起点距离 并对间隔取模 */
  // float u = mod(vDistance + length(canvasPos - vPosition), 30.0);

  float u = mod(vDistance, 30.0);


  if (u > 5.0 && u < 25.0) {
    gl_FragColor = vec4(1.0, 0, 0, 1.0);
    return;
  } else {
    discard;
    // gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
  }
}`;

And my point data as flows:

  const point1 = [
    [100, 100],

    // [200, 200],
    // [300, 300],
    // [400, 400],
    // [500, 500],
    // [600, 600],
    [200, 100],
    [300, 100],
    [400, 100],
    [500, 100],
    [600, 100],
    [700, 100],
    [800, 200],
    [700, 300],
    [700, 400],
    [700, 500],
    [200, 500],
  ];

And the result is:
enter image description here

what confused me is : When the polyline is neither horizontal nor vertical, the red segments are not standard rectangles. I’m wondering if there’s an issue with the code, or if there’s a need to address the direction of interpolation.

how to reset the image bounding box after clipping the image in fabric js v 5.3.0

I am using Fabric JS 5.3.0

and after I clip an image the bounding box (width/height) image is still the original and not equal to the clipped image

What i have tried

i tried setting the image width and height to the cropping box width and height it kind of work i am the bonding box is correct but i moved the clip-path to the top left of the image

MY CODE

  enterCroppingMode() {
            let obj = canvas.getActiveObject();

            this.isCropping = true;

            currentElement = obj;


            croppingBox = new useFabric.Rect({
                left: obj.getBoundingRect().left + 10,
                top: obj.getBoundingRect().top + 10,
                width: obj.getScaledWidth(),
                height: obj.getScaledHeight(),
                fill: "rgba(0,0,0,.3)",
                strokeWidth: 1,
                stroke: "#777",
                strokeUniform: true,
                noScaleCache: false,
                isCropBox: true
            });

            canvas.croppingBoxLeft = croppingBox.left;

            canvas.add(croppingBox);

            canvas.setActiveObject(croppingBox);


            canvas.renderAll();
        },
        cropImage() {
            canvas.setActiveObject(currentElement);

            let obj = canvas.getActiveObject();

            this.selection = obj;
            
            clipPath = new fabric.Rect({
                left: -croppingBox.getScaledWidth(),
                top: -croppingBox.getScaledHeight(),
                width: croppingBox.getScaledWidth() * 2,
                height: croppingBox.getScaledHeight() * 2
            });

            obj.clipPath = clipPath;

            canvas.remove(croppingBox);

            croppingBox = false;
            currentElement = false;
            clipPath = false;
            this.isCropping = false;

           canvas.renderAll()
           
        },

BEFORE CROPPED

AFTER CROPPED

Font ligature for text in node

I am encountering a font ligature issue in a sentence.

The sentence in question is:


Verizon is sunseng BlueJeans as the plaorm struggled to gain tracon against rival services in the video conferencing market


I have a list of ligatures, and some examples are provided here:

const ligatureMap = {
 "": "ti",
 "": "tf",
  ſt: "ft",
 "pla": "platf",
 "AT&amp;T": "AT&T",
}

To address this issue, I am attempting to replace the ligatures using the following code:

return text.replace(/[uE000-uF8FF]/g, (match) => {
    return ligatureMap[match] || match;
});

but it is not converting plaorm to tf and & to &
So how to solve this?

Is it allowed to use an IPv4 as rp_id in webauthn credential creation options?

I am writing a webauthn demonstrator following https://webauthn.guide, and it works well when I host my frontend on https://localhost:4200.’

However, if I host the angular frontend to my local network, and replace rp_id='localhost' with the ip address I can open the frontend with, say, rp_id='198.168.99.99', navigator.credentials.create always gives DOMException: The operation is insecure..

I expected the credential creation to succeed since the ip is part of the URL I open the website with. How can I successfully create the credentials on a website served on my local network?

Can’t properly pass Datetime value through json to asp.net CRUD action

I have this CRUD action on the backend, I mainly use swagger to check it and it works just fine, it just asks for a single JSON pair

{
“dateAssigned”: “2024-01-17T12:41:10.864Z”
}

I really don’t get the problem here as it is just a simple voucher system; the user just copy-pastes the UUID, the ExamVoucher table gets updated as I want, and then error (it is supposed to write some other data and a date to the other table called Exams).

Here is the picture of how it looks on swagger

Swagger CRUD action

So the front-end part is this:

import React, { useState, useContext } from 'react';
import DatePicker from 'react-datepicker'; // make sure to install react-datepicker
import 'react-datepicker/dist/react-datepicker.css'; // Default styling
import AuthContext from '../../AuthContext'; // Adjust path as needed
import { format } from 'date-fns';

const RedeemVoucher = () => {
const [voucherCode, setVoucherCode] = useState('');
const [examDate, setExamDate] = useState(new Date());
const { token } = useContext(AuthContext);

const handleRedeem = async () => {
    try {
        const formattedDate = examDate.toISOString();
        const response = await fetch(`https://localhost:5888/api/ExamVouchers/RedeemVoucher/${voucherCode}`, {
            method: 'PUT',
            headers: {
                "Content-Type": "application/json",
                'Authorization': `Bearer ${token}`,
            },
            body: JSON.stringify({ redeemVoucherDto: { dateAssigned: formattedDate } }) // Adjusted structure
        });

        if (!response.ok) {
            const errorText = await response.text();
            console.error('Response Status:', response.status, 'Response Text:', errorText);
            throw new Error('Network response was not ok');
        }

        alert('Voucher redeemed successfully!');
    } catch (error) {
        console.error('Error redeeming voucher:', error);
        alert('Error redeeming voucher: ' + error.message);
    }
};



return (
    <div className="container">
        <h2>Redeem Voucher</h2>
        <div>
            <input
                type="text"
                className="form-control"
                placeholder="Enter Voucher Code"
                value={voucherCode}
                onChange={(e) => setVoucherCode(e.target.value)}
            />
        </div>
        <div>
            <DatePicker
                selected={examDate}
                onChange={(date) => { console.log(date);setExamDate(date)}}
                showTimeSelect
                //dateFormat="Pp"
            />
        </div>
        <div>
            <button onClick={handleRedeem} className="btn btn-primary">
                Redeem
            </button>
        </div>
    </div>
);
};

export default RedeemVoucher;

and the frontend API is this:

        [Authorize]
    [HttpPut("RedeemVoucher/{voucherCode}")]
    public IActionResult RedeemVoucher(Guid voucherCode, [FromBody] RedeemVoucherDto redeemVoucherDto)
    {
        var userIdClaim = User.Claims.FirstOrDefault(c => c.Type == "id");
        if (userIdClaim == null)
        {
            return Unauthorized("User ID is missing.");
        }
        var userId = int.Parse(userIdClaim.Value);
        var candidate = _context.Candidates.FirstOrDefault(c => c.UserId == userId);

        if (candidate == null)
        {
            return NotFound("Candidate not found.");
        }
        var voucher = _context.ExamVouchers.FirstOrDefault(v => v.VoucherCode == voucherCode);



        if (voucher == null || voucher.IsUsed)
        {

            return Unauthorized("Voucher not found or already used.");
        }

        voucher.CandidateId = candidate.CandidateId;
        voucher.IsUsed = true;
        _context.SaveChanges();

        Exam exam = new Exam
        {
            CandidateId = candidate.CandidateId,
            VoucherId = voucher.VoucherId,
            DateAssigned =  redeemVoucherDto.DateAssigned,
            CertificateId = voucher.CertificateId
        };

        _context.Exams.Add(exam);
        _context.SaveChanges();

        return Ok("Voucher redeemed and exam scheduled.");
    }

of course I tried using many front-end date formats, my database is made of this

CREATE TABLE Exam (
ExamID INT IDENTITY(1,1) PRIMARY KEY,
CandidateID INT,
VoucherID INT, 
DateAssigned DATETIME,
CertificateID INT,
FOREIGN KEY (CandidateID) REFERENCES Candidates(CandidateID),
FOREIGN KEY (CertificateID) REFERENCES Certificate(CertificateID),
FOREIGN KEY (VoucherID) REFERENCES ExamVoucher(VoucherID),
);

SqlTypeException: SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.

If I Console.Writeline I can see that the date that the back-end reads is actually 1/1/0001 12:00

Is there a way to set the starting value of HTML Time’s Time Pickers

Is there a way to set the default starting value of the Time Pickers that pop up when using the HTML time picker.

<input type="time" name="appt-time">

When it has no value it defaults to the users current time. I have tried setting the value using onfocus, but this then actually sets the value, which means when the element loses focus it would have a value set instead of staying null.

angular sticky table box shadows

So I have a sticky table but I only need the box shadow on the second column which is Requestor Name on the right side , I want to remove that shadow I put arrow on the screenshow below because both first and second column are sticky and also the last column is sticky but it looks bad then the Requestor Name column has both boxshadow on left and right.

How do we do that ? Thanks.

table

#html code

 <table
                          mat-table
                          [dataSource]="dataSource"
                          matMultiSort
                          (matSortChange)="requestsListTable.onSortEvent()"                        >

                        <ng-container matColumnDef="requestTitle" sticky>
                          <th mat-multi-sort-header="requestTitle" mat-header-cell *matHeaderCellDef>Request Title</th>
                          <td mat-cell *matCellDef="let element">
                            <div class="checkbox-container td-value-name">
                              <mat-checkbox [checked]="selectedWorkFlowIds.includes(element.workflowApprovalId)" [disabled]="!isAllowedBulkUpdate(element)" class="no-navigation" color="primary" (change)="onChangeSelect(element, $event, 'request')"></mat-checkbox> 
                              <div [matTooltip]="element.requestTitle" class="td-value-name">{{ element.requestTitle?.length > 45 ? element.requestTitle.slice(0,45) + '...' : element.requestTitle }}</div>
                            </div>
                          </td>
                        </ng-container>

                        <ng-container matColumnDef="requestorName">
                          <th mat-multi-sort-header="requestorName" mat-header-cell *matHeaderCellDef>Requestor Name</th>
                          <td mat-cell *matCellDef="let element">
                            <div class="td-value-name">
                              {{element.requestorName}}
                            </div>
                          </td>
                        </ng-container>

                        <ng-container matColumnDef="requestTypeName">
                          <th mat-multi-sort-header="requestTypeName"  mat-header-cell *matHeaderCellDef>Request Type</th>
                          <td mat-cell *matCellDef="let element" >
                            <div class="td-value-name">
                              {{element.requestTypeName }}
                            </div>
                          </td>
                        </ng-container>

                        <ng-container matColumnDef="department">
                          <th mat-multi-sort-header="department" mat-header-cell *matHeaderCellDef>Department</th>
                          <td mat-cell *matCellDef="let element" >
                            <div class="td-value-name">
                              {{element.departmentName}}
                            </div>
                          </td>
                        </ng-container>

                          <ng-container matColumnDef="requestorPriority">
                            <th mat-multi-sort-header="requestorPriority" mat-header-cell *matHeaderCellDef>Requestor Priority</th>
                            <td mat-cell *matCellDef="let element" >
                              <div class="td-value-name">
                                {{element.requestorPriorityString}}
                              </div>
                            </td>
                          </ng-container>
                  
                          <ng-container matColumnDef="projectTeamPriority">
                            <th mat-multi-sort-header="projectTeamPriority" mat-header-cell *matHeaderCellDef>Project Team Data</th>
                            <td mat-cell *matCellDef="let element">
                              <div class="td-value-name">
                                {{element.projectTeamPriority}}
                              </div>
                            </td>
                          </ng-container>
                  
                          <ng-container matColumnDef="requestDate">
                            <th mat-multi-sort-header="requestDate" mat-header-cell *matHeaderCellDef>Request Date</th>
                            <td mat-cell *matCellDef="let element">
                              <div class="td-value-name">
                                {{element.requestDate | date : 'MM/dd/yyyy'}}
                              </div>
                            </td>
                          </ng-container>
                  
                          <ng-container matColumnDef="targetCompletionDate">
                            <th mat-multi-sort-header="targetCompletionDate" mat-header-cell *matHeaderCellDef>Target Completion Date</th>
                            <td mat-cell *matCellDef="let element">
                              <div class="td-value-name">
                                {{element.targetCompletionDate | date : 'MM/dd/yyyy'}}
                              </div>
                            </td>
                          </ng-container>
                          <ng-container matColumnDef="currentStepName">
                            <th mat-multi-sort-header="currentStepName" mat-header-cell *matHeaderCellDef>Current Step Name</th>
                            <td mat-cell *matCellDef="let element" class="align-icon-and-value">
                              <div class="td-value-name current-step-container">
                                <button mat-button (click)="onViewWorkflow($event, element)">
                                  <mat-icon style="padding-right: 10px;">remove_red_eye</mat-icon> {{element.currentStepName}}
                                </button>
                              </div>
                            </td>
                          </ng-container>
                          <ng-container matColumnDef="currentApprover">
                            <th mat-multi-sort-header="currentApprover" mat-header-cell *matHeaderCellDef>Current Approver</th>
                            <td mat-cell *matCellDef="let element">
                              <div class="td-value-name" [matTooltip]="element.currentApproverName">
                                {{ element.currentApproverName?.length > 45 ? element.currentApproverName.slice(0,45) + '...' : element.currentApproverName }}
                              </div>
                            </td>
                          </ng-container>
                          <ng-container matColumnDef="lastStepCompleted">
                            <th mat-multi-sort-header="lastStepCompleted" mat-header-cell *matHeaderCellDef>
                              Last Step Completed
                            </th>
                            <td mat-cell *matCellDef="let element">
                              <div class="td-value-name">
                                {{ element.lastStepCompleted }}
                              </div>
                            </td>
                          </ng-container>

                          <ng-container matColumnDef="onHold">
                            <th mat-header-cell *matHeaderCellDef class="text-center">On Hold</th>
                            <td mat-cell *matCellDef="let element">
                              <div class="text-center">
                                <!-- <mat-icon class="dragCursor" (mousedown)="dragDisabled = false;"
                                  style="color: rgb(146, 146, 146)">drag_indicator</mat-icon> -->
                                <mat-checkbox [disabled]="!isProjectTeamData" class="no-navigation" color="primary"(change)="onChangeSelect(element, $event, 'OnHold')"
                                [checked]="element.isOnHold"></mat-checkbox>
                              </div>
                            </td>
                          </ng-container>
                      
                          <ng-container matColumnDef="status">
                            <th mat-multi-sort-header="status" mat-header-cell *matHeaderCellDef>Status</th>
                            <td mat-cell *matCellDef="let element">
                              <div>
                                {{ element.statusDisplayString }}
                              </div>
                            </td>
                          </ng-container>

                          <ng-container matColumnDef="actions" stickyEnd > 
                            <th mat-header-cell *matHeaderCellDef class="text-center">Actions</th>
                            <td mat-cell *matCellDef="let element" class="text-center">
                              <div class="action-value-name">
                                <div style="display: flex">
                                  <div (click)="approve($event,element)" *ngIf="element.approveButton && isActionAllowed(element)" class="action-item with-divider text-center">
                                    <mat-icon style="color: #65B741;">check</mat-icon>{{element.approveButton}}
                                  </div>  
                                  <div (click)="reject($event,element)" *ngIf="element.rejectButton && isActionAllowed(element)" class="action-item">
                                    <mat-icon style="color: #DF2E38;">close</mat-icon>{{element.rejectButton}}
                                  </div>
                                </div>
                              </div>
                            </td>
                          </ng-container>
                         
                          <tr mat-header-row *matHeaderRowDef="displayedColumnsTableLeft"></tr>
                          <tr mat-row (click)="viewDetails($event, row)" *matRowDef="let row; columns: displayedColumnsTableLeft"></tr>
                        </table>

#css snippet

.text-center {
    text-align: center
}

.cursor-pointer {
    cursor: pointer;
}

.sort-button {
    margin-left: 10px;
}

.search-approval {
    width: 300px;
    margin-right: 10px;
    margin-top: -2px;
}

.center-message {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
}

.no-record {
    margin-top: -60px;
    font-size: 12px;
}

.checkbox-container {
    display: flex;
    align-items: center;
}

.mat-checkbox {
    margin-right: 10px;
    /* Adjust the margin as needed */
}

/* .mat-column-requestorName {
    position: sticky;
    left: 200px;
    z-index: 1;
    background-color: inherit;
} */

/* 
.mat-table-sticky-border-elem-right {
    border-left: 1px solid #e0e0e0;
}

.mat-table-sticky-border-elem-left {
    border-right: 1px solid #e0e0e0;
}

th.mat-column-actions,
td.mat-column-actions {
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

th.mat-column-requestTypeName,
td.mat-column-requestTypeName {
    padding-left: 12px;
}

th.mat-column-requestTitle,
td.mat-column-requestTitle {
    padding-right: 12px;
}

th.mat-column-requestorName,
td.mat-column-requestorName {
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
 */

th.mat-column-actions,
td.mat-column-actions {
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

.mat-column-requestorName {
    position: sticky;
    left: 200px;
    z-index: 1;
    background-color: inherit;
    /* border-right: 1px solid #e0e0e0; */

}

.mat-column-requestTitle     {
    background-color: inherit;
    /* border-right: 1px solid #e0e0e0; */

}

th.mat-column-requestorName,
td.mat-column-requestorName {
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

th.mat-column-requestTypeName,
td.mat-column-requestTypeName {
    padding-left: 12px;
}

How to get keys of zod schema object (`z.ZodObject`)

I have a zod object that is defined like this:

const schema = z.object({
  firstName: z.string().min(1, 'Required'),
  middleName: z.string().optional(),
  lastName: z.string().min(1, 'Required'),
  phoneCountryCode: z.string().min(1, 'Required'),
  phoneNumber: z.string().min(1, 'Required'),
  countryOfResidence: z.string().min(1, 'Required'),
});

How can I extract the keys from the ZodObject?

Obviously, I could define the input object first and then insert it as an argument for z.object

const schemaRawShape = {
  firstName: z.string().min(1, 'Required'),
  middleName: z.string().optional(),
  lastName: z.string().min(1, 'Required'),
  phoneCountryCode: z.string().min(1, 'Required'),
  phoneNumber: z.string().min(1, 'Required'),
  countryOfResidence: z.string().min(1, 'Required'),
} satisfies z.ZodRawShape

const schema = z.object(schemaRawShape);

const keys = Object.keys(infoStepSchemaCommonObj)

However, that becomes more difficult to read and follow as the schema grows more complicated.
For example, when dealing with unions and/or intersections.

Custom sorting in @tanstack/react-table v8

I have a problem with declaring custom sort types.The documentation states the declaration as follows:

declare module '@tanstack/table-core' {
    interface SortingFns {
       myCustomSorting: SortingFn<unknown>
     }
}

I did this in an external .d.ts file. But now this property has become mandatory and must now be specified in useReactTable.

const instance = useReactTable(
    {
        data,
        columns,
        getCoreRowModel: getCoreRowModel(),
        sortingFns: {}
    }
)

Can I somehow declare it so that it is optional?

PUT request with fetch using Vue.js 3

I study frontend development at a vocational college in Stockholm, Sweden. We are currently studying the Javascript framework (vue.js) and I am stuck on a task. In we will build a simple app using an API with in the form of cities and the cities’ population.

In the task, we will build an app where cities can be displayed, added, edited and deleted. GET, POST, PUT and DELETE must therefore be used.
The cities should be displayed directly.
When the content of the data (i.e. when cities are added, edited or removed) the information must be updated automatically.
The page should not be reloaded with, for example, location.reload, but the automatic update should take place via the mechanisms in Vue.js.

This is what i was thinking:
A title, two inputs and a submit button, below this i have a list were all the cities will show when the page in loaded. In every list-item i have the name of the city, population count and two buttons, one edit and one delete. Here is the code for this:

<body>
        <div id="app">
            <h1>Cities API</h1>
            <h3>Add City</h3>
            <div id="city-form">
                <input
                    v-show="isVisible"
                    type="text"
                    placeholder="ID"
                    v-model="id"
                />
                <input
                    type="text"
                    placeholder="City"
                    v-model="name"
                />
                <input
                    type="number"
                    placeholder="Population"
                    v-model="population"
                />
                <input :disabled="!isValid" type="submit" id="submit-btn" @click="submitCity()" >
            </div>
            <div>
                <ul>
                    <li
                        v-for="city in cities"
                        :key="city.id"
                        class="city-item"
                    >
                        <div class="city-info">
                            <p>{{ city.name }}</p>
                            <p>{{ city.population }}</p>
                        </div>
                        <div class="city-actions">
                            <button @click="prepareEditCity(city)">Edit</button>
                            <button
                                class="delete-btn"
                                @click="deleteCity(city.id)"
                            >Delete
                            </button>
                        </div>
                        <hr />
                    </li>
                </ul>
            </div>
        </div>
        <script src="https://unpkg.com/vue@3"></script>
        <script src="index.js"></script>
    </body>

I tried to use everything that we have been talking about (data, created, computed, methods). We have also talked about watch.

First i need to fetch the data that should be rendered in the list when the pages has loaded. For this im using a fetch in my methods. Then im using this function in my created() so the fetch will happen as soon as the page is loaded. I have problem to add a city or to delete a city its when im trying to edit a city with PUT im having problem.

The submit button is connected to a submit function that will know if its a new city or a edited city.

When im clicking on edit on a specific city i get the right name and population in the inputs, i have also logged to see if the fetch is sending the right data and it is. Now the problem is that it doesnt update the city automatic, i have to reload the page after the submit for the city to be edited. This my code for this. Can anyone tell me where the problem is? I dont want the answer or the right code sent to me just tell me how i should think so i can figure this one out.

const app = Vue.createApp({
    data() {
        return {
            cities: null,
            name: '',
            population: '',
            id: '',
            isVisible: false
        }
    },
    created() {
        this.fetchCities()
    },
    computed: {
        isValid() {
            return this.name.length > 0 && this.population > 0
        }
    },
    methods: {
        fetchCities() {
            fetch('https://myapi/cities')
                .then((response) => response.json())
                .then((result) => {
                    this.cities = result
                })
                .catch((error) => {
                    console.error(error, 'Couldt find cities')
                })
        },
        submitCity() {
            if (this.id) {
                this.editCity()
            } else {
                this.addCity()
            }
        },
        addCity() {
            fetch('https://myapi/cities', {
                body: JSON.stringify({
                    name: this.name,
                    population: this.population
                }),
                headers: {
                    'Content-Type': 'application/json'
                },
                method: 'POST'
            })
                .then((response) => response.json())
                .then((result) => {
                    this.fetchCities()
                    this.name = ''
                    this.population = ''
                })
                .catch((error) => {
                    console.error('Could not add city')
                })
        },
        deleteCity(cityId) {
            if (confirm('Are you really sure you want to delete this city?')) {
                fetch(`https://myapi/cities/${cityId}`, {
                    method: 'DELETE'
                })
                    .then(() => {
                        this.fetchCities()
                    })
                    .catch((error) => {
                        console.error('Could not delete city')
                    })
            }
        },
        prepareEditCity(city) {
            this.name = city.name
            this.population = city.population
            this.id = city.id
        },
        editCity() {
            console.log(`Editing city with id: ${this.id}, name: ${this.name}, population: ${this.population}`)
            fetch(`https://myapi/cities/${this.id}`, {
                body: JSON.stringify({
                    name: this.name,
                    population: this.population,
                    id: this.id
                }),
                headers: {
                    'Content-Type': 'application/json'
                },
                method: 'PUT'
            })
                .then((response) => response.json())
                .then((result) => {
                    this.fetchCities()
                    this.name = ''
                    this.population = ''
                    this.id = ''
                })
                .catch((error) => {
                    console.log('Could not edit city')
                })
        }
    }
}).mount('#app')