You are an expert software engineer specialised in Next.js 14 with TypeScript and TailwindCSS. I need you to add an animation when my Feedback component mounts and unmounts.

app/submissions/[submissionUrl]/mark/[assessmentId]/feedbacks.tsx

```
"use client";

import { IQuestionBranch } from "@/app/actions/server/default.action";
import useVisibleElements from "@/hooks/visible-elements.hook";
import React, { useMemo, useState } from "react";
import Feedback from "./feedback";
import { IContent } from "@/database/schemas/content.schema";
import { createHierarchicalLabel } from "@/lib/utils";

interface IProps {
  question: IQuestionBranch;
  dependency: { [key: string]: string };
}

const Feedbacks = ({ question, dependency }: IProps) => {
  const visibleElementIds = useVisibleElements();

  const [feedbacks, setFeedbacks] = useState(initFeedbacks(question));
  const [activeFeedback, setActiveFeedback] = useState<string | null>(null);

  // eslint-disable-next-line
  const visibleQuestionIds = useMemo(() => getVisibleQuestionIds(dependency, visibleElementIds), [visibleElementIds]);

  const visibleFeedbacks = feedbacks.filter((el) => visibleQuestionIds.indexOf(el.questionId) !== -1);

  return (
    <>
      {visibleFeedbacks.map((el) => (
        <Feedback
          key={`question-${el.questionId}-feedback`}
          isActive={activeFeedback === el.questionId}
          onClick={setActiveFeedback.bind(this, el.questionId)}
          {...el}
        />
      ))}
    </>
  );
};

export default Feedbacks;

export interface IFeedback {
  questionId: string;
  label: string;
  grade: string;
  feedback: IContent[];
}

const initFeedbacks = (question: IQuestionBranch): IFeedback[] => {
  const newFeedbacks: IFeedback[] = [];
  const addFeedback = (feedbacks: IFeedback[], questionBranch: IQuestionBranch, trail: number[] = []): void => {
    if (questionBranch.grade === undefined || !questionBranch.feedback) throw new Error("");
    feedbacks.push({
      questionId: questionBranch.id,
      label: trail.length > 0 ? `Question ${createHierarchicalLabel(trail)}` : "Assessment",
      grade: questionBranch.grade,
      feedback: questionBranch.feedback,
    });
    for (let i = 0; i < questionBranch.questions.length; i++) {
      addFeedback(feedbacks, questionBranch.questions[i], [...trail, i]);
    }
  };
  addFeedback(newFeedbacks, question);
  return newFeedbacks;
};

const getVisibleQuestionIds = (dependency: { [key: string]: string }, visibleElementIds: string[]): string[] => {
  // Convert the visibleElementIds array to a Set for efficient lookups
  const visibleSet = new Set(visibleElementIds);

  // Iterate over the keys of the dependency object
  // and filter keys whose corresponding value is in the visibleSet
  return Object.keys(dependency).filter((key) => visibleSet.has(dependency[key]));
};
```

app/submissions/[submissionUrl]/mark/[assessmentId]/feedback.tsx

```
import ContentsView from "@/components/c-ui/contents/view";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import React from "react";
import { IFeedback } from "./feedbacks";
import { IContent } from "@/database/schemas/content.schema";

interface IProps extends IFeedback {
  isActive: boolean;
  onClick: () => void;
}

const Feedback = ({ questionId, label, grade, feedback, isActive, onClick }: IProps) => {
  const state: "empty" | "preview" | "active" = isActive ? "active" : !grade && !feedback.length ? "empty" : "preview";

  let description: string;

  switch (state) {
    case "empty":
      description = "Add feedback";
      break;
    case "preview":
      description = "Edit feedback";
      break;
    case "active":
      description = "Editing in progress";
      break;
    default:
      throw new Error("");
  }

  return (
    <Card className="opacity-60 hover:opacity-100" onClick={onClick}>
      <CardHeader>
        <CardTitle>{label}</CardTitle>
        <CardDescription>{description}</CardDescription>
      </CardHeader>
      {state === "preview" && <Preview questionId={questionId} grade={grade} feedback={feedback} />}
    </Card>
  );
};

export default Feedback;

interface IPreviewProps {
  questionId: string;
  grade: string;
  feedback: IContent[];
}

const Preview = ({ questionId, grade, feedback }: IPreviewProps) => {
  return (
    <CardContent className="h-fit w-full flex flex-col">
      <p>
        Grade: <span>{grade}</span>
      </p>
      <p>Feedback:</p>
      <ContentsView keyPrefix={`question-${questionId}-feedback`} contents={feedback} />
    </CardContent>
  );
};
```